Unix C程序——套接字和选择函数
我刚刚开始学习UnixC编程,有一个问题我无法解决。在这个程序中,我用socket和select函数制作了一个简单的服务器。当我使用不同的终端启动试图连接服务器的客户端程序时,服务器可以接受新的客户端并成功连接。根据我的代码,打印一个句子。然而,当我试图通过scanf和send-in-client程序将客户端程序中的消息发送到servers时,服务器只是在那里阻塞,无法接收任何消息。 你能帮我找出程序中的缺陷吗?非常感谢你的建议!! 这是我的服务器程序代码。客户端程序没有问题,我认为:Unix C程序——套接字和选择函数,c,sockets,unix,select,C,Sockets,Unix,Select,我刚刚开始学习UnixC编程,有一个问题我无法解决。在这个程序中,我用socket和select函数制作了一个简单的服务器。当我使用不同的终端启动试图连接服务器的客户端程序时,服务器可以接受新的客户端并成功连接。根据我的代码,打印一个句子。然而,当我试图通过scanf和send-in-client程序将客户端程序中的消息发送到servers时,服务器只是在那里阻塞,无法接收任何消息。 你能帮我找出程序中的缺陷吗?非常感谢你的建议!! 这是我的服务器程序代码。客户端程序没有问题,我认为: 1
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <sys/types.h>
5 #include <sys/socket.h>
6 #include <netinet/in.h>
7 #include <string.h>
8 #include <fcntl.h>
9 #include <sys/select.h>
10 //all kinds of header
11 main(){
12 int sfd; //server's file descriptor
13 int fdall[100]; //array for client descriptor
14 int count=0; //total number of clients
15 int maxfd=0; // max value of all descriptors
16 char buf[1024]={0}; //used for receiving message from client, by recv()
17 fd_set fds; // readset in select()
18 sfd=socket(AF_INET,SOCK_STREAM,0);
19
20 struct sockaddr_in add;
21 add.sin_family=AF_INET;
22 add.sin_port=htons(9999);
23 add.sin_addr.s_addr=inet_addr("192.168.122.1");
24 int i,j,r;
25
26 r=bind(sfd,(struct sockaddr*)&add,sizeof(add));
27 if(r==-1) printf("bind:%m\n"),exit(-1);
28 else puts("bind ok!");
29 listen(sfd,10);
30
31 while(1){
32 FD_ZERO(&fds);
33 maxfd=0;
34 FD_SET(sfd,&fds);
35 maxfd=maxfd>sfd?maxfd:sfd;
36 for(i=0;i<100;i++){
37 fdall[i]=-1;
38 }
39 r=select(maxfd+1,&fds,0,0,0);
40 if(FD_ISSET(sfd,&fds)){
41 fdall[count]=accept(sfd,0,0);
42 puts("new client!");
43 count++;
44 }
45 for(i=0;i<count;i++){
46 if(FD_ISSET(fdall[i],&fds)!=-1&&fdall[i]!=-1){
47 r=recv(fdall[i],buf,1023,0);
48 for(j=0;j<count;j++){
49 if(fdall[j]!=-1){
50 send(fdall[j],buf,r,0);
51 }
52 }
53 }
54 }
55 }
56 }
不能使用scanf从套接字读取数据。scanf将从STDIN读取数据;这就是造成你阻塞的原因。您也不能使用fscanf,因为这需要一个文件*,尽管使用freopen可以从套接字生成一个文件,但它会假定它可以坐在那里读取其核心内容,而不是使用select
您需要做的是从套接字读入缓冲区。当您有适当数量的数据(可能由换行符分隔)时,请使用sscanf note EXTALLED s,确保正在解析的字符串以NUL结尾。当前代码存在以下几个问题: 一,。fds集中始终只有一个套接字集。它是您正在侦听新连接的套接字。您可能也希望将所有连接到客户端的套接字放在那里 二,。测试FD_是setfdall[i],&fds=-1没有意义。FD_ISSETfdall[i],&fds类似于一个布尔值,仅测试是否等于零 三,。您的测试FD_ISSETfdall[i],&fds结果始终为零,因为您已清除fds中除sfd以外的所有值。请注意,select从不向集合中添加文件描述符。它将删除在下一次I/O操作时会阻塞的内容 四,。在每次通过大循环时,您都将fdall[i]设置为-1,尽管之前的值可能是一个打开的套接字,并且您永远不会关闭套接字 在我看来,您需要重新考虑基本功能。在大循环之前,应将fdall[i]设置为-1。在循环中,您应将所有插座从fdall[i]添加到fds。当新客户端连接时,您应在下一个循环迭代中跳过,以避免使用此新套接字测试FD_ISSET,该套接字可能超出调用select的MAXD值。希望有帮助。检查所有库和系统调用的返回值,并打印调试消息以查找错误和意外返回值。这是解决像这样的IO代码问题的第一步。在客户端也可以这样做,而不是scanf,顺便说一句,也许你们应该在这样的应用程序中使用fgets。