我有以下简单程序,一个是服务器,一个是客户端,源代码如下(我已删除错误处理以使代码简短):
server.c
int main(int argc, char *argv[])
{
int listenfd = 0, connfd = 0, connfd1 =0;
struct sockaddr_in serv_addr;
char sendBuff[1025];
time_t ticks;
int one = 1;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
memset(&serv_addr, '0', sizeof(serv_addr));
memset(sendBuff, '0', sizeof(sendBuff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(12345);
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(listenfd, 10);
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
ticks = time(NULL);
snprintf(sendBuff, sizeof(sendBuff), "%.24s\n", ctime(&ticks));
write(connfd, sendBuff, strlen(sendBuff));
close(connfd);
close(listenfd);
printf("existing...\n");
}
client.c:
int main(int argc, char *argv[])
{
int sockfd = 0, n = 0;
char recvBuff[1024];
struct sockaddr_in serv_addr;
fd_set rset;
fd_set wset;
fd_set eset;
struct timeval tv;
int nready;
int count;
if(argc != 2)
{
printf("\n Usage: %s <ip of server> \n",argv[0]);
return 1;
}
memset(recvBuff, '0',sizeof(recvBuff));
sockfd = socket(AF_INET, SOCK_STREAM, 0));
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(12345);
inet_pton(AF_INET, argv[1], &serv_addr.sin_addr);
connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
count = -1;
while(1){
FD_ZERO(&rset);
FD_ZERO(&eset);
FD_SET(sockfd, &rset);
FD_SET(sockfd, &eset);
memset(&tv, 0, sizeof(struct timeval));
tv.tv_sec = 1;
tv.tv_usec = 0;
sleep(1);
count ++;
printf("loopcount is %d\n", count);
nready = select(sockfd + 1, &rset, 0, &eset, &tv);
if(nready < 0){
printf("error in select, exit\n");
exit(-1);
}
if(nready == 0){
printf("nothing ready, continue...\n");
continue;
}
if(FD_ISSET(sockfd, &rset)){
printf("socket read\n");
n = read(sockfd, recvBuff, sizeof(recvBuff) - 1);
if(n < 0){
printf("read error\n");
}else if(n == 0){
printf("zero bytes, we assume it is EOF\n");
}else{
printf("read n = %d\n", n);
recvBuff[n] = 0;
printf("%s\n",recvBuff);
}
}
if(FD_ISSET(sockfd, &eset)){
printf("socket exception\n");
}
}
close(sockfd);
return 0;
}
所以代码非常简单,服务器只是等待第一个客户端,然后它将当前时间写入它,然后服务器将关闭所有FD并退出。 在客户端,它首先连接到服务器,然后它将无限选择此sockfd进行读取和异常。 我的测试机器中的运行结果是:
./client 9.21.63.207
loopcount is 0
socket read
read n = 25
Fri Jun 13 02:50:53 2014
loopcount is 1
socket read
zero bytes, we assume it is EOF
loopcount is 2
socket read
zero bytes, we assume it is EOF
loopcount is 3
socket read
zero bytes, we assume it is EOF
我们可以看到,在服务器退出后,客户端中的选择仍会报告nReady&gt; 0,并且可以读取sockfd,尽管读取返回0,因为我们已达到EOF。我认为这是有道理的。但是当我将这个简单的代码嵌入到一个更大的系统(这是我们公司的产品,大约1.5M代码行)时,在服务器退出后,客户端的选择将报告nReady == 0,请注意,它只返回0,而不是-1,这意味着没有错误....
由于我们的项目非常复杂,我不知道为什么这个简单的代码嵌入更大的系统而不是独立的应用程序时表现不同。我的猜测可能是我们的项目设置了一些影响select行为的全局套接字选项?我不知道,有没有人知道为什么?感谢。