#pragma comment( lib, "ws2_32.lib" )

#include <windows.h>
#include <winsock2.h> // bei manchan compilern muss man nur windows.h includieren (zB VC++)
#include <stdio.h>

#define MAX_CLIENTS 10

int startWinsock(void)
{
  WSADATA wsa;
  return WSAStartup(MAKEWORD(2,0),&wsa);
}

int main()
{
  long rc;
  SOCKET acceptSocket;
  //SOCKET connectedSocket;
  SOCKADDR_IN addr;
  char buf[256];
  char buf2[300];
  // zusätzliche Variabeln
  FD_SET fdSet;
  SOCKET clients[MAX_CLIENTS];
  int i;

  // Winsock starten
  rc=startWinsock();
  if(rc!=0)
  {
    printf("Fehler: startWinsock, fehler code: %d\n",rc);
    return 1;
  }
  else
  {
    printf("Winsock gestartet!\n");
  }

  // Socket erstellen
  acceptSocket=socket(AF_INET,SOCK_STREAM,0);
  if(acceptSocket==INVALID_SOCKET)
  {
    printf("Fehler: Der Socket konnte nicht erstellt werden, fehler code: %d\n",WSAGetLastError());
    return 1;
  }
  else
  {
    printf("Socket erstellt!\n");
  }

  // Socket binden
  memset(&addr,0,sizeof(SOCKADDR_IN));
  addr.sin_family=AF_INET;
  addr.sin_port=htons(12345);
  addr.sin_addr.s_addr=INADDR_ANY; // gewisse compiler brauchen hier ADDR_ANY
  rc=bind(acceptSocket,(SOCKADDR*)&addr,sizeof(SOCKADDR_IN));
  if(rc==SOCKET_ERROR)
  {
    printf("Fehler: bind, fehler code: %d\n",WSAGetLastError());
    return 1;
  }
  else
  {
    printf("Socket an port 12345 gebunden\n");
  }

  // In den listen Modus
  rc=listen(acceptSocket,10);
  if(rc==SOCKET_ERROR)
  {
    printf("Fehler: listen, fehler code: %d\n",WSAGetLastError());
    return 1;
  }
  else
  {
    printf("acceptSocket ist im listen Modus....\n");
  }

  for(i=0;i<MAX_CLIENTS;i++)
  {
    clients[i]=INVALID_SOCKET;
  }

  while(1)
  {
    FD_ZERO(&fdSet); // Inhalt leeren
    FD_SET(acceptSocket,&fdSet); // Den Socket der verbindungen annimmt hinzufügen
   
    // alle gültigen client sockets hinzufügen (nur die die nicht INVALID_SOCKET sind)
    for(i=0;i<MAX_CLIENTS;i++)
    {
      if(clients[i]!=INVALID_SOCKET)
      {
        FD_SET(clients[i],&fdSet);
      }
    }

    rc=select(0,&fdSet,NULL,NULL,NULL); // nicht vergessen den ersten parameter bei anderen betriebssystem anzugeben
    if(rc==SOCKET_ERROR)
    {
      printf("Fehler: select, fehler code: %s\n",WSAGetLastError());
      return 1;
    }
   
    // acceptSocket is im fd_set? => verbindung annehmen (sofern es platz hat)
    if(FD_ISSET(acceptSocket,&fdSet)) {
      // einen freien platz für den neuen client suchen, und die verbingung annehmen
      for(i=0;i<MAX_CLIENTS;i++)
      {
        if(clients[i]==INVALID_SOCKET)
        {
          clients[i]=accept(acceptSocket,NULL,NULL);
          printf("Neuen Client angenommen (%d)\n",i);
          break;
        }
      }
    }

    // prüfen wlecher client sockets im fd_set sind
    for(i=0;i<MAX_CLIENTS;i++)
    {
      if(clients[i]==INVALID_SOCKET)
      {
        continue; // ungültiger socket, d.h. kein verbunder client an dieser position im array
      }
      if(FD_ISSET(clients[i],&fdSet))
      {
        rc=recv(clients[i],buf,256,0);
        // prüfen ob die verbindung geschlossen wurde oder ein fehler auftrat
        if(rc==0 || rc==SOCKET_ERROR)
        {
          printf("Client %d hat die Verbindung geschlossen\n",i);
          closesocket(clients[i]); // socket schliessen         
          clients[i]=INVALID_SOCKET; // seinen platz wieder freigeben
        }
        else
        {
          buf[rc]='\0';
          // daten ausgeben und eine antwort senden
          printf("Client %d hat folgendes gesandt: %s\n",i,buf);
          // antwort senden
          sprintf(buf2,"Du mich auch %s\n",buf);
          send(clients[i],buf2,(int)strlen(buf2),0);
		}
	  }
	}
  }
}
