my client program first connects to server,then server send a file and then client enters a command and send it to server and receives result.i want to implement this by non-blocking io for input command and non-blocking socket.
but my program can not read input from stdin.when i set only stdin in read_set it works but in this case it doesn’t work.
this is my client code:
main (int argc, char *argv[])
{
int len, rc,max_sd;
int sockfd;
int on=1;
char recv_buff[100]="";
char command[100]="";
char result[100]="";
char instr_buff[100]="";
struct sockaddr_in addr;
struct timeval timeout;
fd_set read_set,write_set;
/*************************************************/
/* Create an AF_INET stream socket */
/*************************************************/
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("socket() failed");
exit(-1);
}
rc = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,(char *)&on, sizeof(on)); // Allow socket descriptor to be reuseable
if(rc<0)
{
perror("setsockopt() failed");
close(sockfd);
exit(-1);
}
//Set socket to be non-blocking.
rc = ioctl(sockfd, FIONBIO, (char *)&on);
if(rc<0)
{
perror("ioctl() faild");
close(sockfd);
exit(-1);
}
//making stdin to be non-blocking
rc = ioctl(0, FIONBIO, (char *)&on);
if(rc<0)
{
perror("ioctl() faild");
close(sockfd);
exit(-1);
}
/*************************************************/
/* Initialize the socket address structure */
/*************************************************/
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(SERVER_PORT);
/*************************************************/
/* Connect to the server */
/*************************************************/
int count=0;
do
{
rc = connect(sockfd,(struct sockaddr *)&addr,sizeof(struct sockaddr_in));
count++;
}while(rc<0&&count<20);
if(rc<0)
{
printf("can not connect to server\n");
exit(-1);
}
else
printf("Connect completed.\n");
timeout.tv_sec = 60;
timeout.tv_usec = 0;
FD_ZERO(&read_set);
FD_ZERO(&write_set);
FD_SET(sockfd,&read_set);
FD_SET(0,&read_set);
while(1)
{
rc=select(sockfd+1,&read_set,&write_set,NULL,&timeout);
if(rc<0)
{
perror("select failed()\n");
break;
}
if(rc==0)
{
printf("select timed out.End Program\n");
break;
}
if(FD_ISSET(sockfd,&write_set))
{
//sending data
rc=send(sockfd,command,strlen(command)+1,0);
if(rc<0)
{
perror("sending command failed");
break;
}
if(rc==0)
{
printf("connection closed by server\n");
break;
}
printf("command send\n");
FD_CLR(sockfd,&write_set);
}
if(FD_ISSET(sockfd,&read_set))
{
//receiving data
rc=recv(sockfd,recv_buff,sizeof(recv_buff),0);
if (rc < 0)
{
if(errno == EAGAIN||errno == EWOULDBLOCK)
{
printf("no message\n");
continue;
}
perror(" recv() failed");
break;
}
if(rc==0)
{
printf("connection closed by server\n");
break;
}
//data received
printf("data received\n");
//check to see if is instr.conf or result
if(recv_buff[strlen(recv_buff)-1]=='@') //is file
{
//save to instr_buff
strcpy(instr_buff,recv_buff);
}
else
{
//result received
printf("Result:\n");
printf("%s",recv_buff);
}
printf("Enter Command:\n");
}
if(FD_ISSET(0,&read_set))
{
scanf("%s",command);
FD_SET(sockfd,&write_set);
}
}//end of while
close(sockfd);
}
Remember that
selectupdates the read, write, and exceptionfd_setitems you pass in. This means that if you select on two possible inputs and one of them is ready, the read set has only one bit set in it:How many file descriptors will the second
selectcall check? With only one “ready to read”, the first call cleared the bit for the other descriptor.Note that your loop never re-initializes
read_set. So even though you don’t have twoselectcalls directly in a row, you are in effect callingselectwith some bit(s) cleared on the second and later trips through the loop.(One typical idiom when using
selectis to have “master sets” that you use for inputs, and copy them to be modified in the call:and then use
FD_ISSETon ©_reads and ©_writes as needed. Or, you can useFD_ZEROand rebuild the entire set on each trip through the loop. Another way to bypass this issue entirely is to usepoll, or evenepollor kqueues or similar.)