9
回答
帮忙测试linux c socket TCP返回时间程序有无问题
华为云数据库免费试用   

unix网络编程第六章i\o复用:select和poll函数

6.7和6.8小节代码,不过将服务端改为回射时间(客户端结束连接,在服务器端没做相应处理)。

一个客户发送数据到服务端可以获取返回时间并显示,多个客户端就不行了,真不知道哪地方有问题,调试了好久···

服务器端:

#define PORT 13
#define LISTEN 1024
#define MAXLINE 4096

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <sys/select.h>

int main(int argc,char **argv)
{
	int i,maxi,maxfd,listenfd,connfd,sockfd;
	int nready,client[FD_SETSIZE];
	ssize_t n;
	time_t ticks;
	fd_set rset,allset;
	char buf[MAXLINE];
	socklen_t clilen;
	struct sockaddr_in cliaddr,servaddr;

	if((listenfd=socket(AF_INET,SOCK_STREAM,0))==-1)
	{
		printf("socket error!\n");
		exit(1);
	}

	bzero(&servaddr,sizeof(servaddr));
	servaddr.sin_port=htons(PORT);
	servaddr.sin_family=AF_INET;
	servaddr.sin_addr.s_addr=htonl(INADDR_ANY);

	if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr))==-1)
	{
		printf("bind error!\n");
		exit(1);
	}
	if(listen(listenfd,LISTEN)==-1)
	{
		printf("listen error!\n");
		exit(1);
	}
	
	maxfd=listenfd;
	maxi=-1;

	for(i=0;i<FD_SETSIZE;i++)
	{
		client[i]=-1;
	}
	FD_ZERO(&allset);
	FD_SET(listenfd,&allset);
	//printf("fd_setsize:%d\n",FD_SETSIZE);
	for(;;)
	{
		rset=allset;
		if((nready=select(maxfd+1,&rset,NULL,NULL,NULL))==-1)
		{
			printf("select error!\n");
			exit(1);
		}

		if(FD_ISSET(listenfd,&rset))
		{
			clilen=sizeof(cliaddr);
			connfd=accept(listenfd,(struct sockaddr*)&cliaddr,&clilen);
			//printf("accept:%d\n",connfd);
			for(i=0;i<FD_SETSIZE;i++)
			{
				if(client[i]<0)
				{
					client[i]=connfd;
					//printf("client[i]=%d,i=%d\n",client[i],i);
					break;
				}
			}
			FD_SET(connfd,&allset);
			if(connfd>maxfd)
				maxfd=connfd;
			if(i>maxi)
				maxi=i;
			//printf("maxfd=%d,maxi=%d\n",maxfd,maxi);
			if(--nready<=0)
				continue;
		}
		for(i=0;i<=maxi;i++)
		{
			if((sockfd=client[i])<0)
				continue;
			if(FD_ISSET(sockfd,&rset))
			{
				//sleep(5);
				//printf("%d,socket:%d\n",i,sockfd);
				ticks=time(NULL);
				snprintf(buf,sizeof(buf),"%.24s\r\n",ctime(&ticks));
				write(sockfd,buf,sizeof(buf));
				if(--nready<=0)
					break;
			}
		}
//		for(i=0;i<maxi;i++)
//			if((sockfd=client[i])>=0)
//				printf("%d",sockfd);
	}
}

客户端:

#define PORT 13
#define MAXLINE 4096
#define ADDR "127.0.0.1"
#define max(x,y) (((x)>(y))?(x):(y))
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>

void str_cli(FILE *fp,int sockfd);
int main(int argc,char **argv)
{
	int sockfd;
	struct sockaddr_in servaddr;
	char sendline[MAXLINE];
	char recvline[MAXLINE];
	bzero(&servaddr,sizeof(servaddr));
	servaddr.sin_family=AF_INET;
	servaddr.sin_port=htons(PORT);
	servaddr.sin_addr.s_addr=inet_addr(ADDR);
	if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
	{
		printf("socket error!\n");
		exit(1);
	}
	if(connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr))==-1)
	{
		printf("connect error!\n");
		exit(1);
	}
/*	while(fgets(sendline,MAXLINE,stdin)!=NULL)
	{
		write(sockfd,sendline,sizeof(sendline));
		if(read(sockfd,recvline,sizeof(recvline))==0)
		{
			printf("no recv!\n");
			exit(1);

		}
		fputs(recvline,stdout);
	}*/
	str_cli(stdin,sockfd);
}

void str_cli(FILE *fp,int sockfd)
{
	int maxfdp1,stdineof=0;
	fd_set rset;
	char buf[MAXLINE];
	int n;

	FD_ZERO(&rset);
	for(;;)
	{
		if(stdineof==0)
			FD_SET(fileno(fp),&rset);
		FD_SET(sockfd,&rset);
		maxfdp1=max(fileno(fp),sockfd)+1;
		select(maxfdp1,&rset,NULL,NULL,NULL);
		if(FD_ISSET(sockfd,&rset))
		{
			if((n=read(sockfd,buf,MAXLINE))==0)
			{
				if(stdineof==1)
					return;
				else
				{
					printf("read error!\n");
					exit(1);
				}
				write(fileno(stdout),buf,n);
			}
		}
		if(FD_ISSET(fileno(fp),&rset))
		{
			if((n=read(fileno(fp),buf,MAXLINE))==0)
			{
				stdineof=1;
				shutdown(sockfd,SHUT_WR);
				FD_CLR(fileno(fp),&rset);
				continue;
			}
			write(sockfd,buf,n);
		}
	}
}

<无标签>
举报
zino
发帖于6年前 9回/380阅
共有9个答案 最后回答: 6年前

引用来自“中山野鬼”的答案

你这个代码运行一边客户端的,是挂上了一个还是多个?
同一台机器,一个终端窗口运行server,其他终端窗口运行client,不知道有没理解你的意思
你理解一下 select 的工作原理,和为什么需要 FD_ZERO(&rset);其他地方另说。你这样测试和学习,很痛苦的。

引用来自“中山野鬼”的答案

你理解一下 select 的工作原理,和为什么需要 FD_ZERO(&rset);其他地方另说。你这样测试和学习,很痛苦的。
select()的机制中提供一fd_set的数据结构,实际上是一long类型的数组, 每一个数组元素都能与一打开的文件句柄(不管是Socket句柄,还是其他 文件或命名管道或设备句柄)建立联系, 当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执 行了select()的进程哪一Socket或文件可操作。 FD_ZERO(&rset)对数据集置零初始化啊!

引用来自“中山野鬼”的答案

还有个问题。你client write ,server我没看到read
数据已到达由内核修改fd_set通知,server不读取不可以?我来修改看是不是这个原因

你这种写法我没有试过。反正我不这么干。如果是不可知交互过程的我会开线程另外处理。

”我怀疑你的问题是同样的client尝试同时连接。而你前面的connect没有被释放掉。“

不好意思,是我的实验错了。。。。。不是这个情况。

 

引用来自“中山野鬼”的答案

还有个问题。你client write ,server我没看到read
server端当socket有数据到达时,描述符集rset相关位置1,FD_ISSET检测到后进行处理。处理完后哪个函数或操作引发了描述符集该 位的置0呢?如果没有置0,FD_ISSET始终能检测到,造成出错!修改server,FD_ISSET(sockfd,&rset)后增加read函数,程序正常了

引用来自“zino”的答案

引用来自“中山野鬼”的答案

还有个问题。你client write ,server我没看到read
server端当socket有数据到达时,描述符集rset相关位置1,FD_ISSET检测到后进行处理。处理完后哪个函数或操作引发了描述符集该 位的置0呢?如果没有置0,FD_ISSET始终能检测到,造成出错!修改server,FD_ISSET(sockfd,&rset)后增加read函数,程序正常了
这种书上的写法,建议不要折腾。OS能做的事情,不要自己操刀。
顶部