1> 使用select完成TCP客户端程序
客户端:
#include<myhead.h>
#define FPORT 9999
#define FIP "192.168.125.130"
#define KPORT 6666
#define KIP "192.168.125.130"
int main(int argc, const char *argv[])
{
//创建套接字文件描述符
int cfd = 0;
if((cfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
{
perror("socket error");
return -1;
}
//允许重复引用
int reuse = 1;
if(setsockopt(cfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)) == -1)
{
perror("setsockopt error");
return -1;
}
//绑定客服端
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(KPORT);
sin.sin_addr.s_addr = inet_addr(KIP);
if(bind(cfd,(struct sockaddr*)&sin,sizeof(sin)) == -1)
{
perror("bind error");
return -1;
}
//连接服务器
struct sockaddr_in cin;
cin.sin_family = AF_INET;
cin.sin_port = htons(FPORT);
cin.sin_addr.s_addr = inet_addr(FIP);
if(connect(cfd,(struct sockaddr*)&cin,sizeof(cin)) == -1)
{
perror("connect");
return -1;
}
//定义检测文件描述符的集合
fd_set readfd;
//清空集合
FD_ZERO(&readfd);
//将cfd和0加入集合
FD_SET(cfd,&readfd);
FD_SET(0,&readfd);
char buf[128] = "";
int res = -1;
fd_set tempfd;
while(1)
{
tempfd = readfd;
res = select(cfd+1,&tempfd,NULL,NULL,NULL);
if(res < 0)
{
perror("select error");
return -1;
}else if(res == 0)
{
printf("time out\n");
return -1;
}
//下面为处理的处理描述符
if(FD_ISSET(0,&tempfd))
{
bzero(buf,sizeof(buf));
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1]=0;
send(cfd,buf,sizeof(buf),0);
printf("客服端输入为%s\n",buf);
}
if(FD_ISSET(cfd,&tempfd))
{
bzero(buf,sizeof(buf));
int res = recv(cfd,buf,sizeof(buf),0);
if(res == 0)
{
printf("服务器下线\n");
break;
}
printf("服务器发来的消息为%s\n",buf);
}
}
close(cfd);
return 0;
}
服务器:
#include<myhead.h>
#define PORT 9999
#define IP "192.168.125.130"
int main(int argc, const char *argv[])
{
int sfd = -1;
if((sfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
{
perror("socket");
return -1;
}
int reuse = 1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)) == -1)
{
perror("setsockopt error");
return -1;
}
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)) == -1)
{
perror("bind error");
return -1;
}
if(listen(sfd,128) == -1)
{
perror("listen error");
return -1;
}
struct sockaddr_in cin;
socklen_t socklen = sizeof(cin);
int newfd = -1;
char buf[128] = "";
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sfd,&readfds);
FD_SET(0,&readfds);
int res = 0;
fd_set tempfds;
int maxfd = sfd;
char rbuf[128]="";
struct sockaddr_in arr_cin[1024];
while(1)
{
tempfds = readfds;
res = select(maxfd+1,&tempfds,NULL,NULL,NULL);
if(res == -1)
{
perror("select error");
return -1;
}else if(res == 0)
{
printf("time out\n");
return -1;
}
for(int index=0;index<=maxfd;index++)
{
if(!FD_ISSET(index,&tempfds))
{
continue;
}
if(index == sfd)
{
if((newfd = accept(sfd,(struct sockaddr*)&cin,&socklen)) == -1)
{
perror("accept");
return -1;
}
arr_cin[newfd] =cin;
printf("[%s:%d]链接成功,newfd = %d\n\n",inet_ntoa(arr_cin[newfd].sin_addr),ntohs(arr_cin[newfd].sin_port),newfd);
FD_SET(newfd,&readfds);
if(newfd > maxfd)
{
maxfd = newfd;
}
}else if(index == 0)
{
scanf("%s",buf);
printf("%s\n",buf);
}else
{
bzero(rbuf,sizeof(rbuf));
int res = recv(index,rbuf,sizeof(rbuf),0);
if(res == 0)
{
printf("客户端下线\n");
close(index);
FD_CLR(index,&readfds);
for(int i =maxfd;i>0;i--)
{
if(FD_ISSET(i,&readfds))
{
maxfd = i;
break;
}
}
continue;
}
printf("[%s:%d] :%s\n",inet_ntoa(arr_cin[index].sin_addr),ntohs(arr_cin[index].sin_port),rbuf);
strcat(rbuf,"*_*");
send(index,rbuf,sizeof(rbuf),0);
}
}
}
close(sfd);
return 0;
}
效果图:
2> 使用poll完成TCP并发服务器
客户端:
#include<myhead.h>
#define SERPORT 9999
#define SERIP "192.168.125.130"
#define CLIPORT 6666
#define CLIIP "192.168.125.130"
int main(int argc, const char *argv[])
{
int cfd = -1;
if((cfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
{
perror("socket error");
return -1;
}
printf("cfd = %d\n",cfd);
int reuse = 1;
if(setsockopt(cfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)) == -1)
{
perror("setsockopt error");
return -1;
}
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(CLIPORT);
sin.sin_addr.s_addr = inet_addr(CLIIP);
if(bind(cfd,(struct sockaddr*)&sin,sizeof(sin)) == -1)
{
perror("bind error");
return -1;
}
struct sockaddr_in cin;
cin.sin_family = AF_INET;
cin.sin_port = htons(SERPORT);
cin.sin_addr.s_addr = inet_addr(SERIP);
if(connect(cfd,(struct sockaddr*)&cin,sizeof(cin)) == -1)
{
perror("connect error");
return -1;
}
struct pollfd fds[2];
fds[0].fd = 0;
fds[0].events = POLLIN;
fds[1].fd = cfd;
fds[1].events = POLLIN;
int res = -1;
char wbuf[128] = "";
while(1)
{
res = poll(fds,2,-1);
if(res < 0)
{
perror("poll error");
return -1;
}else if(res == 0)
{
printf("time out \n");
return -1;
}
if(fds[0].revents == POLLIN)
{
bzero(wbuf,sizeof(wbuf));
fgets(wbuf,sizeof(wbuf),stdin);
wbuf[strlen(wbuf)-1]=0;
send(cfd,wbuf,sizeof(wbuf),0);
}
if(fds[1].revents == POLLIN)
{
bzero(wbuf,sizeof(wbuf));
int res = recv(cfd,wbuf,sizeof(wbuf),0);
if(res == 0)
{
printf("服务器已下线\n");
break;
}
printf("[%s:%d]:%s\n",SERIP,SERPORT,wbuf);
}
}
close(cfd);
return 0;
}
服务器:
#include<myhead.h>
#define PORT 9999
#define IP "192.168.125.130"
int main(int argc, const char *argv[])
{
//定义套接字文件描述符
int cfd = -1;
if((cfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
{
perror("socket error");
return -1;
}
//端口快速重用
int reuse = 1;
if(setsockopt(cfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)) == -1)
{
perror("setsockopt error");
return -1;
}
//绑定服务器套接字信息并连接
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(IP);
if(bind(cfd,(struct sockaddr*)&sin,sizeof(sin)) == -1)
{
perror("bind error");
return -1;
}
//设置为监听状态
if(listen(cfd,128) == -1)
{
perror("listen error");
return -1;
}
//要检测的文件描述符集合对应的数组
struct pollfd fds[1024];
//定义客户端信息
struct sockaddr_in add_cin[1024];
//标准0
fds[0].fd = 0;
fds[0].events = POLLIN;
//标准cfd
fds[cfd].fd = cfd;
fds[cfd].events = POLLIN;
struct sockaddr_in cin;
socklen_t socklen = sizeof(cin);
int newfd = -1;
int res = -1;
int size = 4;//初始成员个数
char buf[128]="";
while(1)
{
res = poll(fds,size,-1);
if(res == -1)
{
perror("poll error");
return -1;
}else if(res == 0)
{
printf("time out\n");
return -1;
}
for(int index=0;index<1024;index++)
{
if(fds[index].revents != POLLIN)
{
continue;
}
if(fds[cfd].revents == POLLIN)
//if((fds[index].revents == POLLIN)&&(fds[index].fd == cfd))
{
//到此下面为操作文件描述符
//设置为等待连接状态
if((newfd = accept(cfd,(struct sockaddr*)&cin,&socklen)) == -1)
{
perror("accept error");
return -1;
}
//客户端加入数组
add_cin[newfd]=cin;
fds[size].fd = newfd;
fds[size].events = POLLIN;
size++;
//printf("连接成功\n");
printf("[%s,%d]连接成功,newfd=%d\n",inet_ntoa(add_cin[newfd].\
sin_addr),ntohs(add_cin[newfd].sin_port),newfd);
}
else if((fds[index].revents == POLLIN)&&fds[index].fd == 0)
{
bzero(buf,sizeof(buf));
//终端输入
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1] = 0;
printf("服务器输入为%s\n",buf);
}
else
{
bzero(buf,sizeof(buf));
int resa = recv(fds[index].fd,buf,sizeof(buf),0);
if(resa == 0)
{
printf("客户端下线\n");
close(fds[index].fd);
fds[index] = fds[size];
size--;
continue;
}
printf("[%s,%d]发送%s\n",inet_ntoa(add_cin[newfd].sin_addr),\
ntohs(add_cin[newfd].sin_port),buf);
strcat(buf,"*_*");
send(fds[index].fd,buf,sizeof(buf),0);
}
}
}
return 0;
}
服务器:
#include<myhead.h>
#define PORT 9999
#define IP "192.168.125.130"
int main(int argc, const char *argv[])
{
//定义套接字文件描述符
int cfd = -1;
if((cfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
{
perror("socket error");
return -1;
}
//端口快速重用
int reuse = 1;
if(setsockopt(cfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)) == -1)
{
perror("setsockopt error");
return -1;
}
//绑定服务器套接字信息并连接
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(IP);
if(bind(cfd,(struct sockaddr*)&sin,sizeof(sin)) == -1)
{
perror("bind error");
return -1;
}
//设置为监听状态
if(listen(cfd,128) == -1)
{
perror("listen error");
return -1;
}
//要检测的文件描述符集合对应的数组
struct pollfd fds[1024];
//定义客户端信息
struct sockaddr_in add_cin[1024];
//标准0
fds[0].fd = 0;
fds[0].events = POLLIN;
//标准cfd
fds[cfd].fd = cfd;
fds[cfd].events = POLLIN;
struct sockaddr_in cin;
socklen_t socklen = sizeof(cin);
int newfd = -1;
int res = -1;
int size = 4;//初始成员个数
char buf[128]="";
while(1)
{
res = poll(fds,size,-1);
if(res == -1)
{
perror("poll error");
return -1;
}else if(res == 0)
{
printf("time out\n");
return -1;
}
for(int index=0;index<1024;index++)
{
if(fds[index].revents != POLLIN)
{
continue;
}
if(fds[cfd].revents == POLLIN)
{
//到此下面为操作文件描述符
//设置为等待连接状态
if((newfd = accept(cfd,(struct sockaddr*)&cin,&socklen)) == -1)
{
perror("accept error");
return -1;
}
//客户端加入数组
add_cin[newfd]=cin;
fds[newfd].fd = newfd;
fds[newfd].events = POLLIN;
size++;
//printf("连接成功\n");
printf("[%s,%d]连接成功,newfd=%d\n",inet_ntoa(add_cin[newfd].\
sin_addr),ntohs(add_cin[newfd].sin_port),newfd);
}
else if((fds[index].revents == POLLIN)&&fds[index].fd == 0)
{
bzero(buf,sizeof(buf));
//终端输入
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1] = 0;
printf("服务器输入为%s\n",buf);
}
else
{
bzero(buf,sizeof(buf));
int resa = recv(fds[index].fd,buf,sizeof(buf),0);
if(resa == 0)
{
printf("客户端下线\n");
close(fds[index].fd);
//fds[index] = fds[size];
//size--;
continue;
}
printf("[%s,%d]发送%s\n",inet_ntoa(add_cin[newfd].sin_addr),\
ntohs(add_cin[newfd].sin_port),buf);
strcat(buf,"*_*");
send(fds[index].fd,buf,sizeof(buf),0);
}
}
}
return 0;
}
效果图: