Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /***************************************************************************
- Name: selectchatsrv.cpp
- Autor: www.c-worker.ch
- Comments: deutsch/english
- Beschreibung:
- Zeigt wie man blocking calls umgehen kann indem man select verwendet.
- Mit select() kann ein Server geschrieben werden welcher mehrere Clients handelt,
- ohne mehrere Threads zu erzeugen.
- Beim diesem Demo handelt es sich um einen kleinen Chat-Server der auf Port 1234
- läuft. Der client dazu heisst selectchatclient.cpp
- Description:
- Show how to use select() to write a server which handles multiple clients in
- just one thread. It's a little chat server which runs on port 1234, the client
- is named selectchatclient.cpp
- ***************************************************************************/
- // max. Anzahl Clients
- // dynamisch konfigurierbar?
- #define MAX_CLIENTS 100
- // Der Standartwert für FD_SETSIZE ist 64, dieser kann aber verändert
- // werden indem man FD_SETSIZE auf einen anderen Wert setzt bevor man
- // winsock2.h includiert.
- // FD_SETSIZE auf die max. Anzahl Clients setzten
- // The default value of FD_SETSIZE is 64, which can be modified by
- // defining FD_SETSIZE to another value before including Winsock2.h.
- // set FD_SETSIZE to the max. number of clients
- #define FD_SETSIZE MAX_CLIENTS
- // includes...
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <windows.h>
- #include <winsock2.h>
- #include <conio.h>
- // configuration file
- LPCSTR ini = "./server.ini";
- // Stellt eine Verbindung mit einem Client dar
- // Represents a connection with a Client
- struct Connection {
- Connection() {
- used=false;
- socket=INVALID_SOCKET;
- }
- void set(SOCKET s, SOCKADDR_IN addr) {
- this->socket=s;
- this->addr=addr;
- this->used=true;
- }
- void erase() {
- this->used=false;
- this->socket=INVALID_SOCKET;
- }
- bool used; // connection benutzt ? / connection slot used ?
- SOCKET socket; // socket
- SOCKADDR_IN addr; // client addr
- };
- // clients
- Connection clients[MAX_CLIENTS];
- // Sucht den nächsten freien Platz im clients Array
- // -1 = kein platz frei
- // Searches the next free slot in the clients array
- // -1 = no free slot
- int getFreeClientSlot() {
- for(int i=0;i<MAX_CLIENTS;i++) {
- if(clients[i].used==false)
- return i;
- }
- return -1;
- }
- // Sendet eine Nachricht an alle Clients
- // Send's a Message to all clients
- int sendToAllClients(char* msg) {
- int rc,i;
- for(i=0;i<MAX_CLIENTS;i++) {
- if(!clients[i].used)
- continue;
- rc=send(clients[i].socket,msg,strlen(msg),0);
- if(rc==SOCKET_ERROR) {
- printf("Error: Sending to Client %d failed: %d\n",i,WSAGetLastError());
- }
- }
- return 0;
- }
- int sendToAllClients2(char* msg, int dontsend) {
- int rc,i;
- for(i=0;i<MAX_CLIENTS;i++) {
- if(!clients[i].used)
- continue;
- if(i==dontsend)
- continue;
- rc=send(clients[i].socket,msg,strlen(msg),0);
- if(rc==SOCKET_ERROR) {
- printf("Error: Sending to Client %d failed: %d\n",i,WSAGetLastError());
- }
- }
- return 0;
- }
- // Startet Winsock und gibt einige Infos zur Version aus
- // Starts winsock and dumps some infos about the version
- int startWinsock(int p) {
- int rc;
- WSADATA wsaData;
- rc=WSAStartup(MAKEWORD(2,0),&wsaData);
- //printf("Return Code: %d\n",rc);
- if(rc==SOCKET_ERROR) {
- printf("Error, exiting!\n");
- return rc;
- }
- printf("[BOOT] LANChat\n[INFO] Server auf Port %d gestartet\n", p);
- /*
- printf("Version: %d.%d\n",LOBYTE(wsaData.wVersion),HIBYTE(wsaData.wVersion));
- printf("High Version: %d.%d\n",LOBYTE(wsaData.wHighVersion),HIBYTE(wsaData.wHighVersion));
- printf("Description: %s\n",wsaData.szDescription);
- printf("System Status: %s\n",wsaData.szSystemStatus);
- */
- return 0;
- }
- // main...
- int main(int argc, char *argv[]) {
- // SOCKET welcher neue Verbindungen annimmt
- SOCKET acceptSocket;
- SOCKADDR_IN addr;
- int rc, addrsize=sizeof(SOCKADDR_IN);
- unsigned int i,j;
- // read serverport from config file
- char returnValue[100];
- GetPrivateProfileString("serversettings", "port", 0, returnValue, 100, ini);
- int serverport = atoi(returnValue);
- fd_set fdSetRead;
- // timout für select()
- timeval selectTimeout;
- // temporär benutz für neue verbindungen
- Connection newConnection;
- // buffer
- char buf[1024];
- // clients array leeren / clear clients array
- memset(clients,0x0,sizeof(Connection)*MAX_CLIENTS);
- // start winsock
- rc=startWinsock(serverport);
- if(rc==SOCKET_ERROR)
- return 1;
- // socket erstellen / create socket
- acceptSocket=socket(PF_INET,SOCK_STREAM,0);
- if(acceptSocket==INVALID_SOCKET) {
- printf("Error, cannot create socket: %d\n",WSAGetLastError());
- return 1;
- }
- // sockt an port 1234 binden / bind socket to port 1234
- memset(&addr,0,sizeof(SOCKADDR_IN));
- addr.sin_family=AF_INET;
- addr.sin_port=htons(serverport);
- addr.sin_addr.s_addr=ADDR_ANY;
- rc=bind(acceptSocket,(SOCKADDR*)&addr,sizeof(SOCKADDR_IN));
- if(rc==SOCKET_ERROR) {
- printf("Error, bind() failed: %d\n",WSAGetLastError());
- return 1;
- }
- // auf verbindungen warten / listen for connections
- rc=listen(acceptSocket,10);
- if(rc==SOCKET_ERROR) {
- printf("Error,listen() failed: %d\n",WSAGetLastError());
- return 1;
- }
- // The parameter readfds identifies the sockets that are to be checked for readability.
- // If the socket is currently in the listen state, it will be marked as readable if an
- // incoming connection request has been received such that an accept is guaranteed to
- // complete without blocking.
- while(1) {
- // fd_set leeren!!!
- FD_ZERO(&fdSetRead);
- // den socket welcher verbindungen annimmt hinzufügen
- FD_SET(acceptSocket,&fdSetRead);
- // alle clients hinzufügen
- for(i=0;i<MAX_CLIENTS;i++) {
- if(clients[i].used)
- FD_SET(clients[i].socket,&fdSetRead);
- }
- // warten bis irgend ein socket bereit ist, wenn timout NULL ist kehrt select()
- // erst zurück wenn ein socket bereit ist, select() blockt also in diesem falle
- rc=select(0,&fdSetRead,NULL,NULL,NULL);
- // break on error
- if(rc<1)
- break;
- for(i=0;i<fdSetRead.fd_count;i++) {
- // acceptSocket ?
- if(fdSetRead.fd_array[i]==acceptSocket) {
- // verbindung annehmen / accept new connection
- newConnection.socket=accept(acceptSocket,(SOCKADDR*)&newConnection.addr,&addrsize);
- rc=getFreeClientSlot();
- if(rc==-1) {
- printf("Cannot accept new clients\n");
- continue;
- }
- //printf("[INFO] Client #%d added\n",rc);
- // zu den clients hinzufügen
- // add to clients
- /*
- char new_client_msg[] = "[SERVER] client from ";
- strcat(new_client_msg, inet_ntoa(newConnection.addr.sin_addr));
- sendToAllClients(new_client_msg);
- */
- clients[rc]=newConnection;
- clients[rc].used=true;
- // welcome banner senden
- char msg[100];
- GetPrivateProfileString("serversettings", "banner", 0, msg, 100, ini);
- //strcat(msg,"\n");
- send(newConnection.socket,msg,strlen(msg),0);
- char stau[] = "[INFO] new Client from ";
- strcat(stau,inet_ntoa(newConnection.addr.sin_addr));
- sendToAllClients2(stau, rc);
- printf("%s\n",stau);
- continue;
- }
- // ein client ?
- for(j=0;j<MAX_CLIENTS;j++) {
- if(!clients[j].used)
- continue;
- if(clients[j].socket==fdSetRead.fd_array[i]) {
- rc=recv(clients[j].socket,buf,1023,0);
- buf[rc]='\0';
- // rc==0 => client hat die verbindung beendet
- // rc==0 => client closed connection
- if(rc==0) {
- printf("Client %d (%s): connection closed\n",j,inet_ntoa(clients[j].addr.sin_addr));
- closesocket(clients[j].socket);
- clients[j].erase();
- continue;
- // rc==SOCKET_ERROR => fehler, verbindung beenden!
- // rc==SOCKET_ERROR => error, close connection!
- } else if(rc==SOCKET_ERROR) {
- //printf("Client %d (%s): Error %d\n",j,inet_ntoa(clients[j].addr.sin_addr),WSAGetLastError());
- printf("Client %d (%s): connection aborted\n",j,inet_ntoa(clients[j].addr.sin_addr));
- char client_gone[] = "[SERVER] Client leaves: ";
- strcat(client_gone,inet_ntoa(clients[j].addr.sin_addr));
- sendToAllClients2(client_gone, j);
- closesocket(clients[j].socket);
- clients[j].erase();
- continue;
- // daten empfangen und an alle clients senden
- // receive data and send it to all clients
- } else {
- printf("Client %d (%s): '%s' \n",j,inet_ntoa(clients[j].addr.sin_addr),buf);
- sendToAllClients(buf);
- }
- }
- }
- }
- }
- // aufräumen
- closesocket(acceptSocket);
- WSACleanup();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement