Tcp echo chat server для нескольких клиентов в windows.
I have a problem in case of multiple clients socket programming in c++. Actually I have downloaded a source code for server side that echo the message to the clients. Also I have a simple client code. Everything works perfectly as long as there is only one client connected to the server. But when the other client connects, the server echo the message to both of them but, in the client side it prints in different order. Indeed it wait for user to enter the input message and then print out the received message. But I want it to be print it as soon as the message is received. For better description of the problem, the output of chat between two clients connected to the server is mentioned bellow. Also the codes of server and client are attached at the end. in the Bob cmd: Pleas insert your message: Bob: hello alice. The recieved message:Bob: hello alice. Pleas insert your message: Bob: how is everything? The recieved message:Alice: hello bob. Pleas insert your message: Bob: everything is perfect! The recieved message:Bob: how is everything?Alice: it is fine, and you? Pleas insert your message: in the alice cmd: Pleas insert your message: Alice: hello bob. The recieved message:Bob: hello alice. Pleas insert your message: Alice: it is fine, and you? The recieved message:Alice: hello bob.Bob: how is everything? Pleas insert your message: Alice: cool! The recieved message:Alice: it is fine, and you?Bob: everything is perfect! Pleas insert your message:
Что я уже пробовал:
/* TCP Echo server in winsock */ #include<stdio.h> #include<winsock2.h> #pragma comment(lib, "ws2_32.lib") //Winsock Library int main(int argc , char *argv[]) { WSADATA wsa; SOCKET master , new_socket , client_socket[30] , s; struct sockaddr_in server, address; int max_clients = 30 , activity, addrlen, i, valread; //size of our receive buffer, this is string length. int MAXRECV = 1024; //set of socket descriptors fd_set readfds; //1 extra for null character, string termination char *buffer; char msg[10] = "salam"; buffer = (char*) malloc((MAXRECV + 1) * sizeof(char)); for(i = 0 ; i < 30;i++) { client_socket[i] = 0; } printf("\nInitialising Winsock..."); if (WSAStartup(MAKEWORD(2,2),&wsa) != 0) { printf("Failed. Error Code : %d",WSAGetLastError()); exit(EXIT_FAILURE); } printf("Initialised.\n"); //Create a socket if((master = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET) { printf("Could not create socket : %d" , WSAGetLastError()); exit(EXIT_FAILURE); } printf("Socket created.\n"); //Prepare the sockaddr_in structure server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons( 8888 ); //Bind if( bind(master ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR) { printf("Bind failed with error code : %d" , WSAGetLastError()); exit(EXIT_FAILURE); } puts("Bind done"); //Listen to incoming connections listen(master , 3); //Accept and incoming connection puts("Waiting for incoming connections..."); addrlen = sizeof(struct sockaddr_in); while(TRUE) { //clear the socket fd set FD_ZERO(&readfds); //add master socket to fd set FD_SET(master, &readfds); //add child sockets to fd set for ( i = 0 ; i < max_clients ; i++) { s = client_socket[i]; if(s > 0) { FD_SET( s , &readfds); } } //wait for an activity on any of the sockets, timeout is NULL , so wait indefinitely activity = select( 0 , &readfds , NULL , NULL , NULL); if ( activity == SOCKET_ERROR ) { printf("select call failed with error code : %d" , WSAGetLastError()); exit(EXIT_FAILURE); } //If something happened on the master socket , then its an incoming connection if (FD_ISSET(master , &readfds)) { if ((new_socket = accept(master , (struct sockaddr *)&address, (int *)&addrlen))<0) { perror("accept"); exit(EXIT_FAILURE); } //inform user of socket number - used in send and receive commands printf("New connection , socket fd is %d , ip is : %s , port : %d \n" , new_socket , inet_ntoa(address.sin_addr) , ntohs(address.sin_port)); //send( new_socket , msg , valread , 0 ); //send( new_socket, msg, (int)strlen(msg), 0 ); //add new socket to array of sockets for (i = 0; i < max_clients; i++) { if (client_socket[i] == 0) { client_socket[i] = new_socket; printf("Adding to list of sockets at index %d \n" , i); break; } } } //else its some IO operation on some other socket :) for (i = 0; i < max_clients; i++) { s = client_socket[i]; //if client presend in read sockets if (FD_ISSET( s , &readfds)) { //get details of the client getpeername(s , (struct sockaddr*)&address , (int*)&addrlen); //Check if it was for closing , and also read the incoming message //recv does not place a null terminator at the end of the string (whilst printf %s assumes there is one). valread = recv( s , buffer, MAXRECV, 0); if( valread == SOCKET_ERROR) { int error_code = WSAGetLastError(); if(error_code == WSAECONNRESET) { //Somebody disconnected , get his details and print printf("Host disconnected unexpectedly , ip %s , port %d \n" , inet_ntoa(address.sin_addr) , ntohs(address.sin_port)); //Close the socket and mark as 0 in list for reuse closesocket( s ); client_socket[i] = 0; } else { printf("recv failed with error code : %d" , error_code); } } if ( valread == 0) { //Somebody disconnected , get his details and print printf("Host disconnected , ip %s , port %d \n" , inet_ntoa(address.sin_addr) , ntohs(address.sin_port)); //Close the socket and mark as 0 in list for reuse closesocket( s ); client_socket[i] = 0; } //Echo back the message that came in else { //add null character, if you want to use with printf/puts or other string handling functions buffer[valread] = '\0'; printf("%s:%d - %s \n" , inet_ntoa(address.sin_addr) , ntohs(address.sin_port), buffer); //for (int j=0;j<4;j++) { send( client_socket[0] , buffer , valread , 0 ); send( client_socket[1] , buffer , valread , 0 ); //printf("%d",client_socket[j]); //} memset(buffer,'\0',sizeof(buffer)); } } } } closesocket(s); WSACleanup(); return 0; }
/* the client side: */ #define WIN32_LEAN_AND_MEAN #define _WIN32_WINNT 0x501 #include <windows.h> #include <winsock2.h> #include <ws2tcpip.h> #include <stdlib.h> #include <stdio.h> #include <iostream> using namespace std; // Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib #pragma comment (lib, "Ws2_32.lib") #pragma comment (lib, "Mswsock.lib") #pragma comment (lib, "AdvApi32.lib") #define DEFAULT_BUFLEN 512 #define DEFAULT_PORT "8888" int __cdecl main(int argc, char **argv) { WSADATA wsaData; SOCKET ConnectSocket; struct addrinfo *result = NULL, *ptr = NULL, hints; char sendbuf[1000]; char recvbuf[DEFAULT_BUFLEN]; int iResult, activity; int recvbuflen = DEFAULT_BUFLEN; // Validate the parameters if (argc != 2) { printf("usage: %s server-name\n", argv[0]); return 1; } // Initialize Winsock iResult = WSAStartup(MAKEWORD(2,2), &wsaData); if (iResult != 0) { printf("WSAStartup failed with error: %d\n", iResult); return 1; } ZeroMemory( &hints, sizeof(hints) ); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; // Resolve the server address and port iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result); if ( iResult != 0 ) { printf("getaddrinfo failed with error: %d\n", iResult); WSACleanup(); return 1; } // Attempt to connect to an address until one succeeds for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) { // Create a SOCKET for connecting to server ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); //printf("%d\n",ConnectSocket); if (ConnectSocket == INVALID_SOCKET) { printf("socket failed with error: %ld\n", WSAGetLastError()); WSACleanup(); return 1; } // Connect to server. iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen); if (iResult == SOCKET_ERROR) { closesocket(ConnectSocket); ConnectSocket = INVALID_SOCKET; continue; } break; } freeaddrinfo(result); if (ConnectSocket == INVALID_SOCKET) { printf("Unable to connect to server!\n"); WSACleanup(); return 1; } while(TRUE) { cout << "Pleas insert your message: "; cin.getline(sendbuf,1000); send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 ); memset(sendbuf,'\0',sizeof(sendbuf)); recv(ConnectSocket, recvbuf, recvbuflen, 0); std::cout << "The recieved message:" << recvbuf <<endl; memset(recvbuf,'\0',sizeof(recvbuf)); } return 0; }