Click here to Skip to main content
16,017,488 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
I wrote a server-client chat for Windows (using threads and non-blocking socket), it works fine with single server but still not supports a few clients. Server works like echo (but only for last connected client). Client.c uses CreateThread function and non-blocking sockets.

I made 3 functions to keep socket values of connected clients in the list, print them and remove when client has left. It works fine:

    struct listElement
{
    SOCKET socket;
    struct listElement *next;
};

struct clientList
{
    struct listElement* head;
};

/*my implementation function, print and remove*/
int pushBackClient(struct clientList *list, SOCKET socket)
void print(struct clientList *list)
int removeFromList(struct clientList *list, SOCKET socket)


Well, this part is done. Now I can collect sockets of every connected client, when client has disconnected its socket is also removed.

But there is still no multiclient support. How should I realise that? I think my code is needed to change a few strings to reach my porpose. And the next question follows from the last: how should orginize my server to send echo-message to ALL the clients except the client who has sent the message?

What I have tried:

server.c

    /* before this cycle there are socket(), listen() and bind() functions */
	while (1)
			{
				FD_ZERO(&readSet);
				FD_SET(listeningSocket, &readSet);
			
				if (newSocketDescriptor)
				{
					FD_SET(newSocketDescriptor, &readSet);
				}
			
				tv.tv_sec = 5;
				retVal = select(listeningSocket + 1, &readSet, NULL, NULL, 0);
				if (retVal == SOCKET_ERROR)
				{
					printf("Select error");
					break;
				}
				else if (retVal == 0)
				{
					printf(". . .\n");
					continue;
				}
				else
				{
					if ((FD_ISSET(listeningSocket, &readSet)) != 0)
					{
						if ((newSocketDescriptor = accept(listeningSocket, (struct sockaddr *)&clientAddr, &clientAddrSize)) == SOCKET_ERROR)
						{
							printf("Accept error ");
							break;
						}
						/* newSocketDescriptor - new connected client, then implement the list */
						pushBackClient(&clientList, newSocketDescriptor);
						print(&clientList);

						FD_ZERO(&readSet);
						FD_SET(newSocketDescriptor, &readSet);
						nclients++; 
						PRINTUSERS

						HOSTENT *hst = gethostbyaddr((const char *)&serverAddr.sin_addr.s_addr, 4, AF_INET);
						printf("Welcome %s (%s:%d) new connected\n", hst->h_name, inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
					}
				
					// READ
					if (FD_ISSET(newSocketDescriptor, &readSet) != 0)
					{
						if ((numBytes = recv(newSocketDescriptor, &bufferData[0], sizeof(bufferData), 0)) == SOCKET_ERROR)
						{
								printf("Recv failed\n");
								break;
						}
						else
						{
							if (!strcmp(&bufferData[0], "quit\n"))
							{
								removeFromList(&clientList, newSocketDescriptor); // if server gets "quit" - remove socket from the list
								newSocketDescriptor = 0;
								nclients--; PRINTUSERS
								printf("Recv failed\n");
								printf("It seems client (%s:%d) has disconnected\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
								FD_ZERO(&readSet);
							}
							else
							{
								bufferData[numBytes] = '\0';
								Sleep(250);
								printf("Client -> Server: %s", &bufferData[0]);
								FD_ZERO(&writeSet);
								FD_SET(newSocketDescriptor, &writeSet);
							}
						}
					}
					// WRITE (send)
					if (FD_ISSET(newSocketDescriptor, &writeSet) != 0)
					{
						if (send(newSocketDescriptor, &bufferData[0], strlen(&bufferData[0]), 0) == SOCKET_ERROR)
						{
							printf("Send error");
							break;
						}
						bufferData[numBytes] = '\0';
						Sleep(250);
						printf("Server -> Client: %s", &bufferData[0]);
					}
				}
			}

Thanks for attention and advices
Posted
Updated 15-May-17 0:58am

1 solution

You need some client managment by extending the structures to save all data. If you know WHO has send the broadcast, than you know to whom NOT to send the broadcast.

A possible solution can be that clients are getting an identifier from the server which the save for the session and sending with each message.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900