1> 使用select实现TCP客户端的并发
#include <myhead.h>
#define SER_PORT 8888
#define SER_IP "192.168.125.64"
#define CLI_PORT 9999
#define CLI_IP "192.168.125.64"
int main(int argc, char const *argv[])
{
//创建用于连接的套接字
int cfd = socket(AF_INET, SOCK_STREAM, 0);
if (cfd == -1)
{
perror("socket error");
return -1;
}
//给套接字绑定端口IP
struct sockaddr_in cin;
cin.sin_family = AF_INET;
cin.sin_port = htons(CLI_PORT);
cin.sin_addr.s_addr = inet_addr(CLI_IP);
//绑定,可选
if (bind(cfd, (struct sockaddr *)&cin, sizeof(cin)) == -1)
{
perror("bind error");
return -1;
}
puts("bind success");
//连接服务器
//填充服务器地址结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(SER_PORT);
sin.sin_addr.s_addr = inet_addr(SER_IP);
if (connect(cfd, (struct sockaddr *)&sin, sizeof(sin)) == -1)
{
perror("bind sin error");
return -1;
}
puts("connect success");
//阻塞客户端
int ret;
fd_set fd;
FD_ZERO(&fd);
FD_SET(0, &fd);
FD_SET(cfd, &fd);
ret = select(cfd + 1, &fd, NULL, NULL, NULL);
char buf[128] = "", buf1[128] = "";
//客户端收发操作
while (1)
{
memset(buf, 0, sizeof(buf));
memset(buf1, 0, sizeof(buf1));
//接收服务器消息事件触发
if (FD_ISSET(cfd, &fd))
{
if (recv(cfd, buf1, sizeof(buf1), 0) < 0)
{
perror("recv error");
return -1;
}
printf("%s\n", buf1);
continue;
}
//发送事件触发
if (FD_ISSET(0, &fd))
{
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf) - 1] = '\0';
if (strcmp(buf, "quit") == 0)
break;
if (send(cfd, buf, strlen(buf), 0) < 0)
{
perror("send error");
return -1;
}
continue;
}
}
END:
//关闭套接字
close(cfd);
return 0;
}
2> 使用poll实现TCP服务器的并发
#include <myhead.h>
#define PORT 8888
#define IP "192.168.125.64"
#define OPEN_MAX 10
int main(int argc, char const *argv[])
{
//创建tcp监听套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
//2.绑定sockfd
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(IP);
if (bind(sockfd, (struct sockaddr *)&sin, sizeof(sin)) == -1)
{
perror("bind error");
return -1;
}
puts("bind success");
//监听listen
if (listen(sockfd, 128) == -1)
{
perror("listen error");
return -1;
}
puts("listen success");
//poll相应参数准备
struct pollfd pfd[OPEN_MAX];
int i = 1, maxi = 1;
//初始化poll结构中的文件描述符fd
for (; i < OPEN_MAX; i++)
pfd[i].fd = -1;
pfd[0].fd = 0;
pfd[0].events = POLLIN;
pfd[1].fd = sockfd;
pfd[1].events = POLLIN;
//对已连接的客户端的数据处理
while (1)
{
//阻塞检测集合中是否有事件产生,-1表示一直阻塞
int ret = poll(pfd, maxi + 1, -1);
struct sockaddr_in cin;
socklen_t socklen = sizeof(cin);
//检测0号描述符
if (pfd[0].revents == POLLIN)
{
//终端输入
char buf[128] = "";
scanf("%s", buf);
if (strcmp(buf, "quit") == 0)
{
break;
}
}
//监测sockfd是否存在连接
if (pfd[1].revents == POLLIN)
{
int res = 0;
//获取客户端
res = accept(sockfd, (struct sockaddr *)&cin, &socklen);
printf("[%s:%d]发来连接请求\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port));
//将提取到的res放入poll结构体数组中,以便于监测
for (i = 2; i < OPEN_MAX; i++)
{
if (pfd[i].fd < 0)
{
pfd[i].fd = res;
pfd[i].events = POLLIN;
break;
}
}
//maxi更新
if (i > maxi)
maxi = i;
//如果没有就绪的描述符,就继续poll监测,否则继续向下看
if (--res <= 0)
continue;
}
//继续响应就绪的描述符
for (i = 2; i <= maxi; i++)
{
if (pfd[i].revents == POLLIN)
{
int len = 0;
char buf[128] = "";
//接受客户端数据
if ((len = recv(pfd[i].fd, buf, sizeof(buf), 0)) < 0)
{
perror("recv error");
return -1;
}
else if (len == 0) //客户端关闭连接
{
puts("客户端下线");
close(pfd[i].fd);
pfd[i].fd = -1;
}
else
{
printf("[%s:%d]%s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), buf);
//正常接收到服务器的数据
strcat(buf, "^.^");
send(pfd[i].fd, buf, sizeof(buf), 0);
}
//所有的就绪描述符处理完了,就退出当前的for循环,继续poll监测
if (--ret <= 0)
break;
}
}
}
close(sockfd);
return 0;
}