服务端:
#include"common.h"
//存放客户端信息的结构体
typedef struct cli_t
{
int cfd;
struct sockaddr_in caddr;
struct cli_t *next;
}cli_t;
int main()
{
struct sockaddr_in caddr,saddr;
int caddr_len;
int fd,ret;
int nfd;
char buf[1024];
int max_fd;
cli_t * head =NULL;
cli_t * pcli;
fd = socket(AF_INET,SOCK_STREAM,0);
printf("socket fd = %d\n",fd);
if(fd < 0)
{
perror("socket");
goto END;
}
saddr.sin_family = AF_INET;
saddr.sin_port = htons(9000);
inet_pton(AF_INET,"192.168.6.125",&saddr.sin_addr.s_addr);
ret = bind(fd,(struct sockaddr *)&saddr,sizeof(saddr));
printf("bind ret = %d\n",fd);
if(ret < 0)
{
perror("bind");
goto END;
}
ret = listen(fd,100);
printf("listen ret = %d\n",fd);
if(ret < 0)
{
perror("listen");
goto END;
}
//清空集合
FD_ZERO(&set);
//放入集合
FD_SET(fd,&set);
max_fd = fd;
while(1)
{
//每次进来用set给rset初始化 保证rset集合里的文件描述符是没受影响的
rset = set;
printf("select...\n");
//select 可能会对集合里的数据产生影响 所以每次selete里我们用rset集合;
ret = select(max_fd+1,&rset,NULL,NULL,NULL);
//我们要保证程序运行要毫无阻塞的回到select 即监听状态 所以下面的read()前面就加了判定 保证每新连接一个客户端 不用阻塞在read()中,然后回到监听状态 这个时候 由于set已经赋给了rset,所以这个时候客户端如果对服务端执行write()操作,select就会监听到这个动作,并解除阻塞状态 程序往下执行 由于这个动作与fd(即连接客户端)无关,所以会跳过accept这一步,并继续往下走,然后循环遍历链表,发现该nfd在rest这个集合中,不会continue,并执行read操作。read()一次后,会再回到select,客户端写一条,服务端读一条并再回到监听状态。这是和服务端中与read相关的动作,而它一共可以监听两个动作,另外一个就是客户端连接动作,所以该程序一共有两条if(FD_ISSET())判断语句,即如果fd在rset中处于可使用状>态,就会accept,如果nfd在rset中处于可使用状态,即客户端正在给服务端write()时,就会read()。实现在不用多线程或多进程的情况下,一个进程中一个线程的服务端同时为多个客户端服务。
printf("select over...\n");//判断是否有客服端连接的动作 fd是sokect返回值
if(FD_ISSET(fd,&rset))
{
//接收链接
caddr_len = sizeof(caddr);
printf("accept...\n");
nfd = accept(fd,(struct sockaddr *)&saddr,&caddr_len);
printf("accept over...\n");
printf("accept nfd = %d\n",nfd);
//声明集合
fd_set set,rset;
// 加入集合
FD_SET(nfd,&set);
max_fd = max_fd > nfd ? max_fd : nfd;
//加入链表
pcli = malloc(sizeof(struct cli_t));
pcli->cfd = nfd;
pcli->caddr = caddr;
pcli->next = head;
head = pcli;}
printf("11111\n");
for(pcli = head;pcli!=NULL;pcli=pcli->next)
{
int tfd = pcli->cfd;
//判断 保证每连接一个客户端 代码走到这里的时候不会被read阻塞
if(!FD_ISSET(tfd,&rset))
continue;
ret = read(tfd,buf,1024);
if(ret <= 0)
{
printf("read ret = 0 tcp broken\n");
//从集合中移除tfd 防止它一直处于运行状态
FD_CLR(tfd,&set);
}
else
{
printf("buf:%s\n",buf);
}
}
}
END:close(fd);
return 0;
}
客户端:
#include"common.h"
void handler()
{
printf("recv sigpipe...\n");
return;
}
int main()
{
struct sockaddr_in saddr;
int fd,ret;
char buf[1024];
signal(SIGPIPE,handler);
fd = socket(AF_INET,SOCK_STREAM,0);
if(fd < 0)
{
perror("socket");
goto END;
}
saddr.sin_family = AF_INET;
saddr.sin_port = htons(9000);
inet_pton(AF_INET,"192.168.6.125",&saddr.sin_addr.s_addr);
printf("connet three handshakes now...\n");
ret = connect(fd,(struct sockaddr *)&saddr,sizeof(saddr));
if(ret < 0)
{
perror("connect");
goto END;
}
printf("connet three handshakes success...\n");
while(1)
{
fgets(buf,1024,stdin);
ret = write(fd,buf,strlen(buf)+1);
if(ret < 0)
{
perror("write");
goto END;
}
}
END:close(fd);
exit(-1);
}
~
~