Advertisement
Guest User

Untitled

a guest
Oct 20th, 2016
58
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.47 KB | None | 0 0
  1. /***************************************************************************
  2. Name: selectchatsrv.cpp
  3. Autor: www.c-worker.ch
  4. Comments: deutsch/english
  5.  
  6. Beschreibung:
  7. Zeigt wie man blocking calls umgehen kann indem man select verwendet.
  8. Mit select() kann ein Server geschrieben werden welcher mehrere Clients handelt,
  9. ohne mehrere Threads zu erzeugen.
  10. Beim diesem Demo handelt es sich um einen kleinen Chat-Server der auf Port 1234
  11. läuft. Der client dazu heisst selectchatclient.cpp
  12.  
  13. Description:
  14. Show how to use select() to write a server which handles multiple clients in
  15. just one thread. It's a little chat server which runs on port 1234, the client
  16. is named selectchatclient.cpp
  17.  
  18. ***************************************************************************/
  19.  
  20.  
  21. // max. Anzahl Clients
  22. // dynamisch konfigurierbar?
  23. #define MAX_CLIENTS 100
  24.  
  25.  
  26. // Der Standartwert für FD_SETSIZE ist 64, dieser kann aber verändert
  27. // werden indem man FD_SETSIZE auf einen anderen Wert setzt bevor man
  28. // winsock2.h includiert.
  29. // FD_SETSIZE auf die max. Anzahl Clients setzten
  30.  
  31. // The default value of FD_SETSIZE is 64, which can be modified by
  32. // defining FD_SETSIZE to another value before including Winsock2.h.
  33. // set FD_SETSIZE to the max. number of clients
  34. #define FD_SETSIZE MAX_CLIENTS
  35.  
  36. // includes...
  37. #include <stdlib.h>
  38. #include <stdio.h>
  39. #include <string.h>
  40. #include <windows.h>
  41. #include <winsock2.h>
  42. #include <conio.h>
  43.  
  44. // configuration file
  45. LPCSTR ini = "./server.ini";
  46.  
  47. // Stellt eine Verbindung mit einem Client dar
  48. // Represents a connection with a Client
  49. struct Connection {
  50. Connection() {
  51. used=false;
  52. socket=INVALID_SOCKET;
  53. }
  54. void set(SOCKET s, SOCKADDR_IN addr) {
  55. this->socket=s;
  56. this->addr=addr;
  57. this->used=true;
  58. }
  59. void erase() {
  60. this->used=false;
  61. this->socket=INVALID_SOCKET;
  62. }
  63. bool used; // connection benutzt ? / connection slot used ?
  64. SOCKET socket; // socket
  65. SOCKADDR_IN addr; // client addr
  66. };
  67.  
  68. // clients
  69. Connection clients[MAX_CLIENTS];
  70.  
  71. // Sucht den nächsten freien Platz im clients Array
  72. // -1 = kein platz frei
  73. // Searches the next free slot in the clients array
  74. // -1 = no free slot
  75. int getFreeClientSlot() {
  76. for(int i=0;i<MAX_CLIENTS;i++) {
  77. if(clients[i].used==false)
  78. return i;
  79. }
  80. return -1;
  81. }
  82.  
  83. // Sendet eine Nachricht an alle Clients
  84. // Send's a Message to all clients
  85. int sendToAllClients(char* msg) {
  86. int rc,i;
  87. for(i=0;i<MAX_CLIENTS;i++) {
  88. if(!clients[i].used)
  89. continue;
  90. rc=send(clients[i].socket,msg,strlen(msg),0);
  91. if(rc==SOCKET_ERROR) {
  92. printf("Error: Sending to Client %d failed: %d\n",i,WSAGetLastError());
  93. }
  94. }
  95. return 0;
  96. }
  97.  
  98. int sendToAllClients2(char* msg, int dontsend) {
  99. int rc,i;
  100. for(i=0;i<MAX_CLIENTS;i++) {
  101. if(!clients[i].used)
  102. continue;
  103. if(i==dontsend)
  104. continue;
  105. rc=send(clients[i].socket,msg,strlen(msg),0);
  106. if(rc==SOCKET_ERROR) {
  107. printf("Error: Sending to Client %d failed: %d\n",i,WSAGetLastError());
  108. }
  109. }
  110. return 0;
  111. }
  112.  
  113. // Startet Winsock und gibt einige Infos zur Version aus
  114. // Starts winsock and dumps some infos about the version
  115. int startWinsock(int p) {
  116. int rc;
  117. WSADATA wsaData;
  118. rc=WSAStartup(MAKEWORD(2,0),&wsaData);
  119. //printf("Return Code: %d\n",rc);
  120. if(rc==SOCKET_ERROR) {
  121. printf("Error, exiting!\n");
  122. return rc;
  123. }
  124.  
  125. printf("[BOOT] LANChat\n[INFO] Server auf Port %d gestartet\n", p);
  126.  
  127. /*
  128. printf("Version: %d.%d\n",LOBYTE(wsaData.wVersion),HIBYTE(wsaData.wVersion));
  129. printf("High Version: %d.%d\n",LOBYTE(wsaData.wHighVersion),HIBYTE(wsaData.wHighVersion));
  130. printf("Description: %s\n",wsaData.szDescription);
  131. printf("System Status: %s\n",wsaData.szSystemStatus);
  132. */
  133. return 0;
  134. }
  135.  
  136. // main...
  137. int main(int argc, char *argv[]) {
  138.  
  139. // SOCKET welcher neue Verbindungen annimmt
  140. SOCKET acceptSocket;
  141. SOCKADDR_IN addr;
  142. int rc, addrsize=sizeof(SOCKADDR_IN);
  143. unsigned int i,j;
  144.  
  145. // read serverport from config file
  146. char returnValue[100];
  147. GetPrivateProfileString("serversettings", "port", 0, returnValue, 100, ini);
  148. int serverport = atoi(returnValue);
  149.  
  150. fd_set fdSetRead;
  151.  
  152. // timout für select()
  153. timeval selectTimeout;
  154.  
  155. // temporär benutz für neue verbindungen
  156. Connection newConnection;
  157. // buffer
  158. char buf[1024];
  159.  
  160. // clients array leeren / clear clients array
  161. memset(clients,0x0,sizeof(Connection)*MAX_CLIENTS);
  162.  
  163. // start winsock
  164. rc=startWinsock(serverport);
  165. if(rc==SOCKET_ERROR)
  166. return 1;
  167.  
  168. // socket erstellen / create socket
  169. acceptSocket=socket(PF_INET,SOCK_STREAM,0);
  170. if(acceptSocket==INVALID_SOCKET) {
  171. printf("Error, cannot create socket: %d\n",WSAGetLastError());
  172. return 1;
  173. }
  174.  
  175. // sockt an port 1234 binden / bind socket to port 1234
  176. memset(&addr,0,sizeof(SOCKADDR_IN));
  177. addr.sin_family=AF_INET;
  178. addr.sin_port=htons(serverport);
  179. addr.sin_addr.s_addr=ADDR_ANY;
  180. rc=bind(acceptSocket,(SOCKADDR*)&addr,sizeof(SOCKADDR_IN));
  181. if(rc==SOCKET_ERROR) {
  182. printf("Error, bind() failed: %d\n",WSAGetLastError());
  183. return 1;
  184. }
  185.  
  186. // auf verbindungen warten / listen for connections
  187. rc=listen(acceptSocket,10);
  188. if(rc==SOCKET_ERROR) {
  189. printf("Error,listen() failed: %d\n",WSAGetLastError());
  190. return 1;
  191. }
  192.  
  193.  
  194. // The parameter readfds identifies the sockets that are to be checked for readability.
  195. // If the socket is currently in the listen state, it will be marked as readable if an
  196. // incoming connection request has been received such that an accept is guaranteed to
  197. // complete without blocking.
  198.  
  199. while(1) {
  200.  
  201. // fd_set leeren!!!
  202. FD_ZERO(&fdSetRead);
  203.  
  204. // den socket welcher verbindungen annimmt hinzufügen
  205. FD_SET(acceptSocket,&fdSetRead);
  206. // alle clients hinzufügen
  207. for(i=0;i<MAX_CLIENTS;i++) {
  208. if(clients[i].used)
  209. FD_SET(clients[i].socket,&fdSetRead);
  210. }
  211.  
  212. // warten bis irgend ein socket bereit ist, wenn timout NULL ist kehrt select()
  213. // erst zurück wenn ein socket bereit ist, select() blockt also in diesem falle
  214. rc=select(0,&fdSetRead,NULL,NULL,NULL);
  215.  
  216. // break on error
  217. if(rc<1)
  218. break;
  219.  
  220. for(i=0;i<fdSetRead.fd_count;i++) {
  221.  
  222. // acceptSocket ?
  223. if(fdSetRead.fd_array[i]==acceptSocket) {
  224. // verbindung annehmen / accept new connection
  225. newConnection.socket=accept(acceptSocket,(SOCKADDR*)&newConnection.addr,&addrsize);
  226. rc=getFreeClientSlot();
  227. if(rc==-1) {
  228. printf("Cannot accept new clients\n");
  229. continue;
  230. }
  231. //printf("[INFO] Client #%d added\n",rc);
  232. // zu den clients hinzufügen
  233. // add to clients
  234. /*
  235. char new_client_msg[] = "[SERVER] client from ";
  236. strcat(new_client_msg, inet_ntoa(newConnection.addr.sin_addr));
  237. sendToAllClients(new_client_msg);
  238. */
  239. clients[rc]=newConnection;
  240. clients[rc].used=true;
  241.  
  242.  
  243. // welcome banner senden
  244. char msg[100];
  245. GetPrivateProfileString("serversettings", "banner", 0, msg, 100, ini);
  246. //strcat(msg,"\n");
  247. send(newConnection.socket,msg,strlen(msg),0);
  248.  
  249. char stau[] = "[INFO] new Client from ";
  250. strcat(stau,inet_ntoa(newConnection.addr.sin_addr));
  251. sendToAllClients2(stau, rc);
  252. printf("%s\n",stau);
  253. continue;
  254. }
  255.  
  256. // ein client ?
  257. for(j=0;j<MAX_CLIENTS;j++) {
  258. if(!clients[j].used)
  259. continue;
  260.  
  261. if(clients[j].socket==fdSetRead.fd_array[i]) {
  262. rc=recv(clients[j].socket,buf,1023,0);
  263. buf[rc]='\0';
  264. // rc==0 => client hat die verbindung beendet
  265. // rc==0 => client closed connection
  266. if(rc==0) {
  267. printf("Client %d (%s): connection closed\n",j,inet_ntoa(clients[j].addr.sin_addr));
  268. closesocket(clients[j].socket);
  269. clients[j].erase();
  270. continue;
  271. // rc==SOCKET_ERROR => fehler, verbindung beenden!
  272. // rc==SOCKET_ERROR => error, close connection!
  273. } else if(rc==SOCKET_ERROR) {
  274. //printf("Client %d (%s): Error %d\n",j,inet_ntoa(clients[j].addr.sin_addr),WSAGetLastError());
  275. printf("Client %d (%s): connection aborted\n",j,inet_ntoa(clients[j].addr.sin_addr));
  276.  
  277. char client_gone[] = "[SERVER] Client leaves: ";
  278. strcat(client_gone,inet_ntoa(clients[j].addr.sin_addr));
  279. sendToAllClients2(client_gone, j);
  280. closesocket(clients[j].socket);
  281. clients[j].erase();
  282. continue;
  283. // daten empfangen und an alle clients senden
  284. // receive data and send it to all clients
  285. } else {
  286. printf("Client %d (%s): '%s' \n",j,inet_ntoa(clients[j].addr.sin_addr),buf);
  287. sendToAllClients(buf);
  288. }
  289. }
  290. }
  291. }
  292. }
  293.  
  294. // aufräumen
  295. closesocket(acceptSocket);
  296. WSACleanup();
  297.  
  298. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement