Reputation: 23
I am just start learning Unix C programming and there is a question I cannot solve. In this program, I made a simple server with socket and select function. When I use different terminals to start client programs which tried to connect server, the server can accept new client and make connection successfully(print a sentence, according to my code). However, when I tried to send message in client program to server(by scanf() and send() ) in client program, the server just block there and no message can be received. Would you please help me find the defect in my program? Thanks very much for any suggestion!! Here is my server program's code( there is no problem in client program, I think):
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 }
Upvotes: 0
Views: 820
Reputation: 7472
There several problems with your current code:
1.) There is always only one socket set in your fds
set. It is the socket where you are listening for new connections. You probably want to put there all sockets connected to clients too.
2.) The test FD_ISSET(fdall[i],&fds)!=-1
has no sense. FD_ISSET(fdall[i],&fds) is something like a boolean value to be tested for equality/disequality to zero only.
3.) Your test FD_ISSET(fdall[i],&fds)
always results to zero, because you have cleared all values (except sfd
) in fds
. Note that select
never adds file descriptors to the set. It removes those which would block on next I/O operation.
4.) At each pass of the big loop you set fdall[i]
to -1
although the previous value may be an open socket and you never close the socket.
It seems to me that you need to rethink the basic functionality. You shall set fdall[i]
to -1
before the big loop. In the loop you shall add all sockets from fdall[i]
to fds
. When a new client connects you shall skip at the next loop iteration in order to avoid testing of FD_ISSET with this new socket (which is probably beyond the value maxfd
for which select was called). Hope it helps.
Upvotes: 0
Reputation: 25129
You cannot use scanf
to read from a socket. scanf
will read from STDIN
; that's what is causing your blocking. You cannot use fscanf
either, as that will require a FILE *
, and though it is possible with freopen
to make a file from a socket, it will assume it can sit there and read
to its heart's content, rather than using select
.
What you will need to do is read
from the socket into a buffer. When you have the appropriate amount of data (perhaps delimited by a newline), then use sscanf
(note additional s
), having ensured the string you are parsing is NUL
terminated.
Upvotes: 1