1. 根据select TCP服务器流程图编写服务器(上交)
include <myhead.h>
#define PORT 8888
#define IP "192.168.43.233"
int stdin_events(void);
int connect_events(int,struct sockaddr_in*,fd_set*,int*);
int recv_send_events(int,struct sockaddr_in*,fd_set*,int*);
int main(int argc, const char *argv[])
{
//创建
int sfd=socket(AF_INET,SOCK_STREAM,0);
if(sfd<0)
{
ERR_MSG("socket");
return -1;
}
printf("创建成功\n");
int reuxe =1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuxe,sizeof(reuxe))<0)
{
ERR_MSG("setsockopt");
return -1;
}
printf("允许端口快速的被复用成功\n");
//绑定
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(PORT);
sin.sin_addr.s_addr=inet_addr(IP);
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR_MSG("bind");
return -1;
}
printf("绑定成功\n");
//设置监听
if(listen(sfd,128)<0)
{
ERR_MSG("listen");
return -1;
}
printf("监听成功\n");
//创建一个读集合和临时读集合
fd_set readfds,tempfds;
//清空
FD_ZERO(&readfds);
//加入stdin和sfd
FD_SET(0,&readfds);
FD_SET(sfd,&readfds);
//定义最大描述符
int maxfd=sfd;
int s_res=-1;
ssize_t res=-1;
char buf[128]="";
//备份连接成功客户端的地址信息
struct sockaddr_in saveCli[1024];
while(1)
{
tempfds=readfds;
s_res=select(maxfd+1,&tempfds,NULL,NULL,NULL);
if(s_res<0)
{
ERR_MSG("select");
return -1;
}else if(0==s_res)
{
printf("超时,自动退出\n");
break;
}
for(int i=0;i<=maxfd;i++)
{
if(0==FD_ISSET(i,&tempfds))
continue;
if(0==i)
{
printf("触发键盘输入事件\n");
stdin_events();
}else if(sfd==i)
{
printf("触发客户端连接事件\n");
connect_events(sfd,saveCli,&readfds,&maxfd);
}else
{
printf("触发客户端交互事件\n");
recv_send_events(i,saveCli,&readfds,&maxfd);
}
}
}
close(sfd);
return 0;
}
//键盘输入事件
int stdin_events(void)
{
char buf[128]="";
bzero(buf,sizeof(buf));
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1]=0;
printf(": %s\n",buf);
return 0;
}
//客户端连接事件
int connect_events(int sfd,struct sockaddr_in *saveCli,fd_set *readfds,int *maxfd)
{
int newfd=-1;
struct sockaddr_in cin;
socklen_t addrlen=sizeof(cin);
newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);
if(newfd<0)
{
ERR_MSG("accept");
return -1;
}
printf("[%s:%d]客户端连接成功 newfd=%d\n",\
inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);
//将cin另存为数组对应下标
saveCli[newfd]=cin;
//将newfd添加到集合
FD_SET(newfd,readfds);
//更新maxfd
*maxfd=*maxfd>newfd?*maxfd:newfd;
return 0;
}
//客户端交互事件
int recv_send_events(int newfd,struct sockaddr_in *saveCli,fd_set *readfds,int *maxfd)
{
char buf[128]="";
bzero(buf,sizeof(buf));
ssize_t res =recv(newfd,buf,sizeof(buf),0);
if(res<0)
{
ERR_MSG("recv");
return -1;
}else if(0==res)
{
printf("[%s:%d]客户端下线 newfd=%d\t%s\n",\
inet_ntoa(saveCli[newfd].sin_addr),ntohs(saveCli[newfd].sin_port),newfd,buf);
close(newfd);
FD_CLR(newfd,readfds);
while(FD_ISSET(*maxfd,readfds)==0&&(*maxfd)-->=0);
return 0;
}
strcat(buf,">.<");
if(send(newfd,buf,sizeof(buf),0)<0)
{
ERR_MSG("send");
return -1;
}
printf("发送成功\n");
return 0;
}
2. 编写select TCP客户端
思维导图:
![](https://i-blog.csdnimg.cn/blog_migrate/75754c3506b6267f5f4e3dc76506e3af.png)