1.select的TCP服务器
代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <sys/un.h>
#include <time.h>
#define IP "192.168.31.160"
#define PORT 8888
#define ERR_MSG(msg) do{\
fprintf(stderr, "__%d__:", __LINE__);\
perror(msg);\
}while(0)
int updateMaxxfd(int maxfd,fd_set readfds);
int main(int argc, const char *argv[])
{
int sfd=socket(AF_INET,SOCK_STREAM,0);
if(sfd<0)
{
ERR_MSG("socket");
return -1;
}
//允许端口快速重用
int reuse=1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0)
{
ERR_MSG("setsockopt");
return -1;
}
printf("快速重用成功\n");
//填充ip和端口到地址信息结构体中,实际结构体由地址族决定
struct sockaddr_in sin;
sin.sin_family=AF_INET;//地址族必须指定为AF_INET
sin.sin_port=htons(PORT);//端口号网络字节序:1024-49151
sin.sin_addr.s_addr=inet_addr(IP);//ubuntu本机ip---ipconfig
//绑定服务器的IP地址和端口,必须绑定
if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
ERR_MSG("bind");
return -1;
}
printf("bind success\n");
//将套接字设置为被动监听状态
if(listen(sfd, 10) < 0)
{
ERR_MSG("listen");
return -1;
}
printf("listen success\n");
fd_set readfds,tempfds;
FD_ZERO(&readfds);
FD_ZERO(&tempfds);
FD_SET(0,&readfds);
FD_SET(sfd,&readfds);
int maxfd=sfd;
int st_res=0;
char buf[128]="";
ssize_t res=0;
struct sockaddr_in cinaddr[1024-4];
int newfd=0;
struct sockaddr_in cin;
socklen_t addrlen=sizeof(cin);
int i=0;
while(1)
{
tempfds=readfds;
st_res=select(maxfd+1,&tempfds,NULL,NULL,NULL);
if(st_res<0)
{
perror("select");
return -1;
}
else if(0==st_res)
{
perror("time out ....\n");
break;
}
printf("触发事件\n");
for(i=0;i<=maxfd;i++)
{
if(FD_ISSET(i,&tempfds)==0)
{
continue;
}
if(0==i)
{
printf("触发键盘输入事件\n");
int sendfd;
bzero(buf,sizeof(buf));
res=scanf("%d %s",&sendfd,buf);
while(getchar()!=10);
if(res!=2)
{
fprintf(stderr,"请输入正确格式:fd string\n");
continue;
}
if(sendfd<=3||FD_ISSET(sendfd,&readfds)==0)
{
fprintf(stderr,"输入文件描述符%d有误\n",sendfd);
continue;
}
if(send(sendfd,buf,sizeof(buf),0)<0)
{
ERR_MSG("send");
return -1;
}
printf("发送成功\n");
}
else if(sfd==i)
{
printf("触发客户端连接事件\n");
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);
FD_SET(newfd,&readfds);
maxfd=maxfd>newfd?maxfd:newfd;
}
else
{
printf("触发客户端交互事件\n");
bzero(buf,sizeof(buf));
res=recv(i,buf,sizeof(buf),0);
if(res<0)
{
ERR_MSG("recv");
return -1;
}
else if(0==res)
{
fprintf(stderr,"[%s:%d]newfd=%d客户端关闭\n",inet_ntoa(cinaddr[i-4].sin_addr),ntohs(cinaddr[i-4].sin_port),i);
close(i);
FD_CLR(i,&readfds);
maxfd=updateMaxxfd(maxfd,readfds);
}
else
{
printf("[%s:%d]newfd=%d 客户端:%s\n",inet_ntoa(cinaddr[i-4].sin_addr),ntohs(cinaddr[i-4].sin_port),i,buf);
}
}
}
}
return 0;
}
int updateMaxxfd(int maxfd,fd_set readfds)
{
for(int j=maxfd;j>=0;j--)
{
if(FD_ISSET(j,&readfds))
{
return j;
}
}
return 0;
}
2.poll的TCP客户端
代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <poll.h>
#define ERR_MSG(msg) do{\
fprintf(stderr, "__%d__:", __LINE__);\
perror(msg);\
}while(0)
#define IP "192.168.31.160"
#define PORT 8888
int main(int argc, const char *argv[])
{
//创建流式套接字
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if(sfd < 0)
{
ERR_MSG("socket");
return -1;
}
//绑定客户端自身的IP地址和端口---->非必须绑定
//填充要连接的服务器的地址信息结构体
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(PORT);
sin.sin_addr.s_addr=inet_addr(IP);
//连接服务器
if(connect(sfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
ERR_MSG("connect");
return -1;
}
printf("connect success\n");
struct pollfd fds[2];
fds[0].fd=0;
fds[0].events=POLLIN;
fds[1].fd=sfd;
fds[1].events=POLLIN;
char buf[128] = "";
ssize_t res ;
int pl_res=0;
while(1)
{
pl_res=poll(fds,2,-1);
if(pl_res<0)
{
ERR_MSG("poll");
return -1;
}
else if(0==pl_res)
{
printf("time out....\n");
break;
}
//fds[0].fd,即0号文件描述符有POLLIN事件产生
if((fds[0].revents&POLLIN)!=0)
{
bzero(buf, sizeof(buf));
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf)-1] = 0;
if(send(sfd, buf, sizeof(buf), 0) < 0)
{
ERR_MSG("send");
return -1;
}
printf("send success\n");
}
//sfd文件描述符有POLLIN事件产生
if((fds[1].revents&POLLIN)!=0)
{
bzero(buf, sizeof(buf));
res = recv(sfd, buf, sizeof(buf), 0);
if(res < 0)
{
ERR_MSG("recv");
return -1;
}
else if(0 ==res)
{
printf("服务器关闭\n");
break;
}
printf("服务器:%s\n", buf);
}
}
close(sfd);
return 0;
}
3.select的TCP客户端
代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <poll.h>
#define ERR_MSG(msg) do{\
fprintf(stderr, "__%d__:", __LINE__);\
perror(msg);\
}while(0)
#define PORT 8888
#define IP "192.168.31.160"
int updateMaxfd(int maxfd, fd_set readfds);
int main(int argc, const char *argv[])
{
//创建流式套接字
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if(sfd < 0)
{
ERR_MSG("socket");
return -1;
}
//绑定客户端自身的IP地址和端口---->非必须绑定
//填充要连接的服务器的IP和端口
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT); //服务器绑定的端口
sin.sin_addr.s_addr = inet_addr(IP); //服务器绑定的IP
//连接服务器
if(connect(sfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
ERR_MSG("connect");
return -1;
}
printf("connect success\n");
//创建集合
fd_set readfds, tempfds;
FD_ZERO(&readfds);
FD_ZERO(&tempfds);
FD_SET(0, &readfds);
FD_SET(sfd, &readfds);
int maxfd = sfd;
int st_res = 0;
char buf[128] = "";
ssize_t res = 0;
struct sockaddr_in cinaddr[1024-4];
struct sockaddr_in cin ;
socklen_t addrlen = sizeof(cin);
int i = 0;
while(1)
{
tempfds = readfds;
//调用select函数
st_res = select(maxfd+1, &tempfds, NULL, NULL, NULL);
if(st_res < 0)
{
perror("select");
return -1;
}
else if(0 == st_res)
{
printf("time out ....\n");
break;
}
for(i=0;i<=maxfd;i++)
{
if(FD_ISSET(i,&tempfds) == 0)
{
continue;
}
if(0==i)
{
int sendfd;
bzero(buf, sizeof(buf));
res=scanf("%s",buf);
while(getchar()!=10);
if(send(sendfd,buf,sizeof(buf), 0)<0)
{
ERR_MSG("send");
return -1;
}
printf("send success\n");
}
else if(sfd == i)
{
if(sfd < 0)
{
ERR_MSG("accept");
return -1;
}
cinaddr[sfd-4] = cin;
FD_SET(sfd, &readfds);
//更新maxfd
maxfd = maxfd>sfd ? maxfd:sfd;
}
else
{
bzero(buf, sizeof(buf));
res=recv(i, buf, sizeof(buf), 0);
if(res< 0)
{
ERR_MSG("recv");
return -1;
}
else if(0 == res)
{
printf("服务器关闭\n");
close(i);
FD_CLR(i, &readfds);
maxfd = updateMaxfd(maxfd, readfds);
}
printf("服务器:%s\n",buf);
}
}
}
close(sfd);
return 0;
}
int updateMaxfd(int maxfd, fd_set readfds)
{
for(int j=maxfd;j>=0;j--)
{
if(FD_ISSET(j, &readfds))
{
return j;
}
}
return 0;
}
终端: