collapse collapse

* Who's Online

  • Dot Guests: 41
  • Dot Hidden: 0
  • Dot Users: 0

There aren't any users online.

* Board Stats

  • stats Total Members: 88
  • stats Total Posts: 11163
  • stats Total Topics: 1699
  • stats Total Categories: 4
  • stats Total Boards: 76
  • stats Most Online: 248

Author Topic: Client-Server Messaging  (Read 106762 times)

0 Members and 3 Guests are viewing this topic.

Offline Jake

  • Newbie
  • *
  • Posts: 5
  • Reputation 0
    • View Profile
Client-Server Messaging
« on: October 25, 2015, 01:57:52 AM »
The server and the client are both platform dependent on linux, I will be working on a windows client later on but for now I have a windows and linux client. I suspect to keep the server on linux only. I integrated 3 new concepts in these programs: threading, sockets, and pointers. These represent the base for a planned multiplayer game, but currently it is a simple multi-client echo messaging server. All done in c++ and possibly some arguable concepts, the results of a lot of trial and error. Any recommendations and pointers are appreciated as always, I doubt it's perfect. The only thing I'm worried about right now is checking for disconnected clients, since connections can "break" and the server would never realize it. Probably some sort of polling would be good for this.

Server:
Code: C++
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <string>
  4. #include <stdlib.h>
  5. #include <sys/socket.h>
  6. #include <arpa/inet.h>
  7. #include <netinet/tcp.h>
  8. #include <unistd.h>
  9. #include <pthread.h>
  10.  
  11. #define MAX_CONNECTIONS 10
  12.  
  13. using namespace std;
  14.  
  15. struct data_t {
  16.         int clientsock;
  17.         int* noClients;
  18.         int* socklist;
  19. };
  20.  
  21. void error(const char *msg)
  22. {
  23.     perror(msg);
  24.     exit(1);
  25. }
  26.  
  27. void *client_handle (void* dataptr)
  28. {
  29.         data_t clientdata = *(data_t*) dataptr;
  30.         char buffer[256];
  31.         int n;
  32.        
  33.         memset(buffer, 0, 256);
  34.         while( (n = recv(clientdata.clientsock, buffer, 255, 0)) > 0 )
  35.         {
  36.                 //Send the message back to client
  37.                 printf("Here is the message: %s\n",buffer);
  38.                 printf("Currently %i clients.\n", *clientdata.noClients);
  39.                 printf("ClientID: %i\n", clientdata.clientsock);
  40.                 for (int i=0;i<MAX_CONNECTIONS;i++) {
  41.                         if(clientdata.socklist[i]!=-1) {
  42.                                 printf("On iteration %i, sending message to clientdata.socklist[%i].\n", i, clientdata.socklist[i]);
  43.                                 n = write(clientdata.socklist[i],buffer,strlen(buffer));
  44.                         }
  45.                 }
  46.                 memset(buffer, 0, 256);
  47.         }
  48.         printf("Caught disconnect!\n");
  49.         for (int i=0;i<MAX_CONNECTIONS;i++) {
  50.                 if (clientdata.socklist[i]==clientdata.clientsock) {
  51.                         clientdata.socklist[i] = -1;
  52.                         break;
  53.                 }
  54.         }      
  55.         *clientdata.noClients = *clientdata.noClients-1;
  56.         close(clientdata.clientsock);
  57.         return dataptr;
  58. }
  59.  
  60. int main(int argc, char *argv[])
  61. {      
  62.         int sock, clientsock, portno;
  63.         socklen_t clilen;
  64.         struct sockaddr_in serv_addr, cli_addr;
  65.         if (argc < 2) {
  66.                 fprintf(stderr,"ERROR, no port provided\n");
  67.                 exit(1);
  68.         }
  69.         sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  70.         if (sock < 0) {
  71.                 error("ERROR opening socket");
  72.         }
  73.         memset((char *) &serv_addr, 0, sizeof(serv_addr));
  74.         portno = atoi(argv[1]);
  75.         serv_addr.sin_family = AF_INET;
  76.         serv_addr.sin_addr.s_addr = INADDR_ANY;
  77.         serv_addr.sin_port = htons(portno);
  78.         if (bind(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
  79.                 error("ERROR on binding");
  80.         }
  81.         int noClients = 0;
  82.         int socklist[MAX_CONNECTIONS];
  83.         for (int i=0; i<MAX_CONNECTIONS; i++) {
  84.                 socklist[i] = -1;
  85.         }
  86.         pthread_t threadA[MAX_CONNECTIONS];
  87.         listen(sock,5);
  88.        
  89.         while (1) { //support 10 clients
  90.                 if (noClients < MAX_CONNECTIONS) {
  91.                         clilen = sizeof(cli_addr);
  92.                         clientsock = accept(sock, (struct sockaddr *) &cli_addr, &clilen);
  93.                         if (clientsock < 0) {
  94.                                 printf("Failed to accept connection!\n");
  95.                                 return 0;
  96.                         }
  97.                         else {
  98.                                 printf("Connection successful!\n");
  99.                         }
  100.                         for (int i=0; i<MAX_CONNECTIONS; i++) {
  101.                                 if (socklist[i]==-1) {
  102.                                         socklist[i] = clientsock;
  103.                                         break;
  104.                                 }
  105.                         }
  106.                         printf("noClients: %i\n", noClients);
  107.                         data_t tosend;
  108.                         tosend.clientsock = clientsock;
  109.                         tosend.noClients = &noClients;
  110.                         tosend.socklist = socklist;
  111.                         noClients++;
  112.                         pthread_create(&threadA[noClients], NULL, client_handle, (void *)&tosend);
  113.                         printf("We should be ready for another connection now.\n");
  114.                 }
  115.                 else {
  116.                         clilen = sizeof(cli_addr);
  117.                         clientsock = accept(sock, (struct sockaddr *) &cli_addr, &clilen);
  118.                         if (clientsock < 0) {
  119.                                 printf("Failed to accept connection!\n");
  120.                                 return 0;
  121.                         }
  122.                         else {
  123.                                 printf("Connection successful... server full\n");
  124.                         }
  125.                         string message = "Sorry, we're currently full! Try again later.";
  126.                         write(clientsock,message.c_str(),strlen(message.c_str()));
  127.                         close(clientsock);
  128.                 }
  129.         }
  130.         close(sock);
  131.         return 0;
  132. }
  133.  

Linux Client:
Code: C++
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <sys/socket.h>
  6. #include <arpa/inet.h>
  7. #include <iostream>
  8. #include <pthread.h> // -lpthread
  9.  
  10.  
  11. using namespace std;
  12.  
  13. void* server_rec(void* dataptr) {
  14.         int sock = *(int*)dataptr;
  15.         char buffer[256];
  16.         memset(buffer, 0, 256);
  17.         while( (recv(sock, buffer, 255, 0)) > 0 )
  18.     {
  19.                 printf("Message Received: %s\n", buffer);
  20.                 memset(buffer, 0, 256);
  21.         }
  22.         printf("Connection to server has been lost, terminating program.\n");
  23.         close(sock);
  24.         exit(0);
  25. }
  26.  
  27.  
  28. int main(int argc , char *argv[])
  29. {
  30.      if (argc < 3) {
  31.          fprintf(stderr,"ERROR, no port/ip provided\n");
  32.          exit(1);
  33.      }
  34.  
  35.         int portno = atoi(argv[1]);
  36.     struct sockaddr_in server;
  37.         int sock;
  38.        
  39.  
  40.         char buffer[256];
  41.         string message;
  42.      
  43.     //Create socket
  44.     sock = socket(AF_INET , SOCK_STREAM , 0);
  45.     if (sock == -1)
  46.     {
  47.         printf("Could not create socket");
  48.     }
  49.      
  50.     server.sin_addr.s_addr = inet_addr(argv[2]);
  51.     server.sin_family = AF_INET;
  52.     server.sin_port = htons( portno );
  53.  
  54.     //Connect to remote server
  55.     if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0)
  56.     {
  57.         perror("Error");
  58.         return 1;
  59.     }
  60.                
  61.         printf("Connected!\n");
  62.        
  63.         pthread_t receive;
  64.         pthread_create(&receive, NULL, server_rec, (void *)&sock);
  65.        
  66.        
  67.     //keep communicating with server
  68.     while(1)
  69.     {
  70.                 memset(buffer, 0, strlen(buffer));
  71.                 std::getline (std::cin,message);
  72.          
  73.         //Send some data
  74.         if( send(sock , message.c_str() , message.length() , 0) < 0)
  75.         {
  76.             printf("Send failure!\n");
  77.             return 1;
  78.         }    
  79.         }
  80.        
  81.     close(sock);
  82.     return 0;
  83. }
  84.  

Windows Client:
Code: C++
  1. #include <iostream>
  2. #include <winsock2.h>
  3. #include <string>
  4. #include <windows.h>
  5. #include <stdio.h>
  6.  
  7. using namespace std;
  8.  
  9. DWORD WINAPI ServerReceive(int sock) {
  10.     SOCKET u_sock = *(SOCKET*)sock;
  11.     char buffer[512];
  12.     while (recv(u_sock,buffer,512,0)!=0) {
  13.         // std::cout<<"Error in Receiving: "<<WSAGetLastError()<<std::endl;
  14.         std::cout << "Message received: " << buffer << "\n";
  15.         memset(buffer, 0, strlen(buffer));
  16.     }
  17.     std::cout << "Connection to server has been lost, terminating program.";
  18.     closesocket(u_sock);
  19.     exit(0);
  20. }
  21.  
  22. int main(int argc , char *argv[])
  23. {
  24.     if (argc < 3) {
  25.         std::cout << "Bad input.";
  26.         return 1;
  27.     }
  28.     int portno = atoi(argv[2]);
  29.     WSAData version;        //We need to check the version.
  30.     WORD mkword=MAKEWORD(2,2);
  31.     int what=WSAStartup(mkword,&version);
  32.     if(what!=0){
  33.         std::cout<<"This version is not supported! - \n"<<WSAGetLastError()<<std::endl;
  34.         return 1;
  35.     }
  36.  
  37.     SOCKET u_sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
  38.     if(u_sock==INVALID_SOCKET) {
  39.         std::cout<<"Creating socket fail\n";
  40.         return 1;
  41.     }
  42.  
  43.     //Socket address information
  44.     sockaddr_in addr;
  45.     addr.sin_family=AF_INET;
  46.     addr.sin_addr.s_addr=inet_addr(argv[1]);
  47.     addr.sin_port=htons(portno);
  48.     /*==========Addressing finished==========*/
  49.  
  50.     //Now we connect
  51.     int conn=connect(u_sock,(SOCKADDR*)&addr,sizeof(addr));
  52.     if(conn==SOCKET_ERROR){
  53.         std::cout<<"Connection error: "<<WSAGetLastError()<<std::endl;
  54.         closesocket(u_sock);
  55.         WSACleanup();
  56.         return 1;
  57.     }
  58.     std::cout << "Connected!\n";
  59.  
  60.     CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ServerReceive, &u_sock, 0, NULL);
  61.  
  62.     char buffer[512];
  63.     string message;
  64.     while(1)
  65.     {
  66.         memset(buffer, 0, strlen(buffer));
  67.         std::getline (std::cin,message);
  68.  
  69.         int smsg=send(u_sock,message.c_str(),message.length(),0);
  70.         if(smsg==SOCKET_ERROR){
  71.             std::cout<<"Error: "<<WSAGetLastError()<<std::endl;
  72.             WSACleanup();
  73.         }
  74.     }
  75.     closesocket(u_sock);
  76.     return 0;
  77. }
  78.  

I'm having some problems while typing a message and receiving at the same time, it mucks up the input by splitting the line with the received message. I've looked into using carriage returns and trying to move the input down while shifting the cout'd receive message up.
« Last Edit: October 25, 2015, 07:03:56 PM by Jake »

Offline Nathan

  • Administrator
  • Hero Member
  • *
  • Posts: 1437
  • Reputation 1768
  • Gender: Male
  • woof woof
    • View Profile
Re: Client-Server Messaging
« Reply #1 on: October 25, 2015, 05:48:57 PM »

Thank you for not using the boost framework. It's overly bloated and wayyyy over the top with namespace usage and complexity. I know many would disagree - but I personally find it easier to read and understand the low level code like this than examples using boost.

You can take a look at the examples I wrote for my Operating Systems class - where I use threads on Windows and Linux:

https://srchub.org/p/os-70-350/source/tree/master/

Or you should also take a look at the ptypes library which has easy to use cross-platform threading and networking.

https://srchub.org/p/ptypes/

Using networking in ptypes is so simple:



Code: C++
  1. #include <pinet.h>
  2.  
  3. USING_PTYPES
  4.  
  5. int main()
  6. {
  7.     ipstream client("www.yahoo.com", 80);
  8.  
  9.     try
  10.     {
  11.         client.open();
  12.  
  13.         // send a valid HTTP/1.1 request
  14.         client.put("GET / HTTP/1.1\r\n"
  15.             "Accept: * /*\r\n"
  16.             "User-Agent: TestAgent/1.0\r\n"
  17.             "Host: www.yahoo.com\r\n"
  18.             "Connection: close\r\n\r\n");
  19.         client.flush();
  20.  
  21.         // receive the response and print it line by line
  22.         while (!client.get_eof())
  23.             pout.putline(client.line());
  24.  
  25.         client.close();
  26.     }
  27.     catch(estream* e)
  28.     {
  29.         perr.putf("Error: %s\n", pconst(e->get_message()));
  30.         delete e;
  31.     }
  32.  
  33.     return 0;
  34. }

Documentation: https://srchub.org/ptypes/inet.examples.html

It also has support for things like mutexes, semaphores, variants, and I recently added support for JSON.

Shameless plug: Feel free to signup for an account/repo on srchub and push your code there. Public and private repositories are free. :)

« Last Edit: October 25, 2015, 05:50:30 PM by Nathan »
Projects:
[ Axios Engine ] [ sourcehub ]
Compilers: Microsoft Visual Studio 2008, GNU C++, FASM, MASM, VB 6/.Net.
Languages: C++, PHP, ASM, JS, VB6/.Net, BASIC, HTML, MySQL
Please buy me some books: Amazon Wishlist

 

Donate


* Search


* Recent Posts

Image Comparison by Shishka
[May 15, 2017, 01:18:02 PM]


Re: srchub - free source code hosting by Nathan
[December 14, 2015, 11:37:02 PM]


Re: srchub - free source code hosting by Celestialkey
[November 27, 2015, 08:51:42 AM]


Updates by Nathan
[October 30, 2015, 08:27:36 PM]


Re: Client-Server Messaging by Nathan
[October 25, 2015, 05:48:57 PM]