C中的多个客户端(聊天)的单个服务器 [英] Single server for multiple clients (chat) in C

查看:145
本文介绍了C中的多个客户端(聊天)的单个服务器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我为 Windows (使用线程和非阻塞套接字)编写了服务器 - 客户端聊天,它适用于单个服务器,但仍然不支持少数客户端。服务器像echo一样工作(但仅适用于最后连接的客户端)。 Client.c使用CreateThread函数和非阻塞套接字。



我做了3个函数来保持列表中连接客户端的套接字值,打印它们并在客户端有删除时删除剩下。它工作正常:



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

struct clientList
{
struct listElement * head;
};

/ *我的实现函数,打印和删除* /
int pushBackClient(struct clientList * list,SOCKET socket)
void print(struct clientList * list)
int removeFromList(struct clientList * list,SOCKET socket)





嗯,这部分已经完成。现在我可以收集每个连接客户端的套接字,当客户端断开连接时,它的套接字也被移除。



但是仍然没有多客户端支持。我该怎么认识到这一点?我认为我的代码需要更改一些字符串才能达到我的目的。下一个问题来自最后一个问题:如何将我的服务器发送到除了发送消息的客户端之外的所有客户端发送echo-message?



我尝试过:



  server.c  

/ *在此循环之前有socket(),listen()和bind()函数* /
而(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(选择错误);
休息;
}
else if(retVal == 0)
{
printf(... .. \ n);
继续;
}
else
{
if((FD_ISSET(listeningSocket,& readSet))!= 0)
{
if((newSocketDescriptor = accept (listeningSocket,(struct sockaddr *)& clientAddr,& clientAddrSize))== SOCKET_ERROR)
{
printf(Accept error);
休息;
}
/ * newSocketDescriptor - 新连接的客户端,然后实现列表* /
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(欢迎%s(%s:%d)new connected\\\
,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\\\
);
休息;
}
else
{
if(!strcmp(& bufferData [0],quit\\\
))
{
removeFromList( & clientList,newSocketDescriptor); //如果服务器获得退出 - 从列表中删除套接字
newSocketDescriptor = 0;
nclients--; PRINTUSERS
printf(Recv failed\\\
);
printf(似乎客户端(%s:%d)断开了\ n,inet_ntoa(clientAddr.sin_addr),ntohs(clientAddr.sin_port));
FD_ZERO(& readSet);
}
else
{
bufferData [numBytes] ='\ 0';
睡眠(250);
printf(客户端 - >服务器:%s,& bufferData [0]);
FD_ZERO(& writeSet);
FD_SET(newSocketDescriptor,& writeSet);
}
}
}
// WRITE(发送)
if(FD_ISSET(newSocketDescriptor,& writeSet)!= 0)
{
if(send(newSocketDescriptor,& bufferData [0],strlen(& bufferData [0]),0)== SOCKET_ERROR)
{
printf(发送错误);
休息;
}
bufferData [numBytes] ='\ 0';
睡眠(250);
printf(服务器 - >客户端:%s,& bufferData [0]);
}
}
}

感谢关注和建议

解决方案

< blockquote>您需要通过扩展结构来保存所有数据,从而进行一些客户端管理。如果您知道世界卫生组织已发送广播,那么您知道谁不发送广播。



可能的解决方案是客户从服务器获取标识符其中保存会话并发送每条消息。


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

解决方案

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.


这篇关于C中的多个客户端(聊天)的单个服务器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆