tcp客户端(ser)操作流程:socket----->bind----->listen----->accept------>recv------->send----->close
注意:操作时客户端cli可使用之前写过TCP通信的cli.c
一、select
①代码
#include "head.h"
int init_tcp_ser(char *ip,unsigned short port)
{
struct sockaddr_in ser;
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == sockfd)
{
perror("fail sockfd");
return -1 ;
}
ser.sin_family = AF_INET;
ser.sin_port = htons(port);
ser.sin_addr.s_addr = inet_addr(ip);
int ret = bind(sockfd,(struct sockaddr *)&ser, sizeof(ser));
if (-1 == ret)
{
perror("fail bind");
exit(1);
}
ret = listen(sockfd, 100);
return sockfd;
}
int main(int argc, char const *argv[])
{
int sockfd = init_tcp_ser("192.168.1.192",50000);//建立套接字
struct sockaddr_in cli;
socklen_t len = sizeof(cli);
fd_set rdfds;
fd_set tmfds;
FD_ZERO(&rdfds);//文件描述符集合清0
FD_SET(sockfd,&rdfds);//将sockfd加入文件描述符集合中
int maxfd = sockfd;
while(1)
{
tmfds = rdfds;
int cnt = select(maxfd + 1,&tmfds,NULL,NULL,NULL);//监测的文件描述符上限值(最大文件描述符的值+1),读文件描述符集合,写文件描述符集合,异常条件的描述符集合,设置超时时间
(NULL:一直等待,直到有事件发生)
if(-1 == cnt)
{
perror("fail select");
return -1;
}
if(FD_ISSET(sockfd,&tmfds))//判断文件描述符sockfd是否仍在文件描述符集合中
{
int connfd = accept(sockfd,(struct sockaddr *)&cli,&len);
if(-1 == connfd)
{
perror("fail accept");
return -1;
}
printf("[%s:%d online]\n",inet_ntoa(cli.sin_addr),ntohs(cli.sin_port));
FD_SET(connfd,&rdfds); //将connfd加入文件描述符集合中
maxfd = connfd > maxfd ? connfd : maxfd;
}
int i = 0;
for(i = sockfd +1 ;i<maxfd;i++)
{
if(FD_ISSET(i,&tmfds))//判断文件描述符i是否仍在文件描述符集合中
{
char buff[1024] = {0};
ssize_t size = recv(i,buff,sizeof(buff),0);
if(size < 0 )
{
perror("fail recv");
FD_CLR(i,&rdfds);// 将i从文件描述符集合中清除
close(i);
continue;
}
else if(0 == size)
{
FD_CLR(i,&rdfds);// 将i从文件描述符集合中清除
close(i);
continue;
}
printf("cli-------->ser:%s\n",buff);
strcat(buff,"-------I kwon\n");
size = send(i,buff,sizeof(buff),0);
if(size <0)
{
perror("fail send");
FD_CLR(i,&rdfds);// 将i从文件描述符集合中清除
close(i);
continue;
}
}
}
}
close(sockfd);
return 0;
}
②操作结果(使用网络调试助手)
二、epoll
①代码
#include "head.h"
int init_tcp_ser(char *ip, unsigned short port)
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == sockfd)
{
perror("fail socket");
exit(1);
}
struct sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_port = htons(port);
ser.sin_addr.s_addr = inet_addr(ip);
int ret = bind(sockfd, (struct sockaddr *)&ser, sizeof(ser));
if (-1 == ret)
{
perror("fail bind");
exit(1);
}
ret = listen(sockfd, 100);
return sockfd;
}
int add_epoll_fd(int epfd,int fd,uint32_t events)
{
struct epoll_event ev;
ev.events = events;
ev.data.fd = fd;
int ret = epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&ev);//EPOLL_CTL_ADD新增事件
if(-1 == ret)
{
perror("fail epoll_ctl add");
return -1;
}
}
int delet_epoll_fd(int epfd,int fd)
{
int ret = epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL);//EPOLL_CTL_DEL 删除事件
if(-1 == ret)
{
perror("epll_ctl del");
return -1;
}
return 0 ;
}
int main(int argc, char const *argv[])
{
struct sockaddr_in cli;
socklen_t len = sizeof(cli);
int sockfd = init_tcp_ser("192.168.1.192",50000);
int epfd = epoll_create(1024);//创建epoll文件描述符集合
if(-1 == epfd)
{
perror("faol epoll_create");
return -1;
}
add_epoll_fd(epfd,sockfd,EPOLLIN);//EPOLLIN 读事件
struct epoll_event evs[1024];
while(1)
{
int epcnt = epoll_wait(epfd,evs,1024,-1);//返回事件的个数,监控io事件
if(-1 == epcnt)
{
perror("fail epoll_wait");
break;
}
int i = 0;
for(i = 0;i<epcnt;i++)
{
if(sockfd == evs[i].data.fd)
{
int connfd= accept(sockfd,(struct sockaddr *)&cli,&len);
if(-1 == connfd)
{
perror("fail accept");
continue;
}
add_epoll_fd(epfd,connfd,EPOLLIN);
}
else
{
char buff[1024] = {0};
ssize_t size = recv(evs[i].data.fd,buff,sizeof(buff),0);
if(-1 == size)
{
perror("fail recv");
delet_epoll_fd(epfd,evs[i].data.fd);
close(evs[i].data.fd);
continue;
}
else if(0 == size)
{
delet_epoll_fd(epfd,evs[i].data.fd);
close(evs[i].data.fd);
continue;
}
printf("cli------ser: %s\n", buff);
strcat(buff,"------------I kwon!\n");
ssize_t s = send(evs[i].data.fd,buff,strlen(buff),0);
if(-1 == s)
{
perror("fail recv");
delet_epoll_fd(epfd,evs[i].data.fd);
close(evs[i].data.fd);
continue;
}
}
}
}
close(sockfd);
return 0;
}
②操作结果
头文件head.h
#ifndef __HEAD_H__ //防止头文件被重复定义
#define __HEAD_H__#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <poll.h>
#include <pthread.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <signal.h>
#include <sys/epoll.h>#endif