[英]Unix C program---socket and select function
我只是開始學習Unix C編程,還有一個我無法解決的問題。 在此程序中,我制作了一個具有套接字和選擇功能的簡單服務器。 當我使用不同的終端啟動嘗試連接服務器的客戶端程序時,服務器可以接受新客戶端並成功建立連接(根據我的代碼打印一句話)。 但是,當我嘗試將客戶端程序中的消息發送到客戶端程序中的服務器(通過scanf()和send())時,服務器只是阻塞在那里,無法接收到任何消息。 您能幫我發現程序中的缺陷嗎? 非常感謝您的任何建議! 這是我的服務器程序的代碼(我認為客戶端程序沒有問題):
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
,因為這將需要FILE *
,並且盡管可以使用freopen
從套接字創建文件,但它將假定它可以坐在那里並read
其內容,而不是使用select
。
您需要做的是從套接字read
緩沖區。 當您有適當數量的數據(也許用換行符分隔)時,請使用sscanf
(請注意其他s
),並確保要解析的字符串是NUL
終止的。
您當前的代碼有幾個問題:
1.) fds
集中始終只有一個套接字集。 它是您正在偵聽新連接的套接字。 您可能還希望將所有連接到客戶端的套接字放在此處。
2.)測試FD_ISSET(fdall[i],&fds)!=-1
沒有意義。 FD_ISSET(fdall [i],&fds)類似於布爾值,僅將相等性/差異性測試為零。
3.)測試FD_ISSET(fdall[i],&fds)
始終為零,因為您已經清除了fds
所有值( sfd
除外)。 請注意, select
從不將文件描述符添加到集合中。 它刪除了將在下一個I / O操作中阻塞的那些。
4.)在大循環的每次通過中,您都將fdall[i]
設置為-1
盡管先前的值可能是打開的套接字,並且您永遠不會關閉套接字。
在我看來,您需要重新考慮基本功能。 您應在大循環之前將fdall[i]
設置為-1
。 在循環中,應將fdall[i]
所有套接字添加到fds
。 當有新的客戶端連接時,您應該跳過下一個循環迭代,以避免使用此新套接字測試FD_ISSET(該套接字可能超出maxfd
調用select的maxfd
值)。 希望能幫助到你。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.