select模型
服务器select模型
/*
* @file server_select.c
* @brief TCP编程API的服务器select模型
* @version 1.1 无
* @author 北豼
* @date 2022年5月21日
*/
#include "net.h"
int main(void)
{
int fd = -1;
struct sockaddr_in sin;
struct timeval tout;
/*1.创建socket fd*/
if ( (fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket");
exit(1);
}
/*2.绑定*/
/*2.1填充struct sockaddr_in结构体变量*/
bzero(&sin, sizeof(sin)); //将struct sockaddr_in结构体变量清零
sin.sin_family = AF_INET;
sin.sin_port = htons(SERV_PORT); //主机字节序的端口号转换为网络字节序的端口号
#if 0
//主机字节序的IP转换为网络字节序的IP
sin.sin_addr.s_addr = inet_addr(SERV_IP_ADDR);
#else
//主机字节序的IP转换为网络字节序的IP
if (inet_pton(AF_INET, SERV_IP_ADDR, (void *)&sin.sin_addr) != 1)
{
perror("inet_pton");
exit(1);
}
#endif
/*2.2绑定*/
if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
perror("bind");
exit(1);
}
/*3.调用listen()把主动套接字变成被动套接字*/
if ( listen(fd, BACKLOG) < 0) //BACKLOG = 5
{
perror("listen");
exit(1);
}
/*4.多路复用*/
fd_set rset;
FD_ZERO(&rset);
//依次把已经建立好连接的fd加入到集合中,记录下来最大的文件描述符maxfd
FD_SET(fd, &rset);
tout.tv_sec = 5;
tout.tv_usec = 0;
int maxfd = -1;
maxfd = fd;
int newfd = -1;
/*5.读写*/
/*和newfd进行数据读写*/
int ret = -1;
char buf[BUFSIZ];
while (1)
{
fd_set tmp = rset;
select(maxfd+1, &tmp, NULL, NULL, &tout);
//判断是不是监听的fd
if (FD_ISSET(fd, &tmp))
{
newfd = accept(fd, NULL, NULL); //后面的两个参数可以接收客户端的属性信息
if (newfd < 0)
{
perror("accept");
exit(1);
}
FD_SET(newfd, &rset);
if (newfd > maxfd)
{
maxfd = newfd;
}
printf("accept sucessfully!\n");
}
for (int i = 0; i <= maxfd; ++i)
{
if (i != fd && FD_ISSET(i, &tmp))
{
bzero(buf, BUFSIZ);
do
{
ret = read(i, buf, BUFSIZ-1);
}while (ret < 0 && EINTR == errno); //如果读取的过程中遇到了中断,则再次从newfd中读取数据到buf中
if (ret < 0)
{
perror("read");
exit(1);
}
if (!ret) //对方已经关闭
{
printf("客户端已经断开连接...\n");
FD_CLR(i, &rset);
close(i);
break;
}
printf("Receive data: %s\n", buf);
if (!strncasecmp(buf, QUIT_STR, strlen(QUIT_STR))) //用户输入了quit字符(忽略大小写)
{
printf("Client is exiting!\n");
break;
}
}
}
}
close(fd);
}
客户端select模型
/*
* @file client_select.c
* @brief TCP编程API的客户端select模型
* @version 1.1
* @author 北豼
* @date 2022年5月14日
*/
#include "net.h"
int main(void)
{
int fd = -1;
struct sockaddr_in sin;
/*1.创建socket fd*/
if ( (fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket");
exit(1);
}
/*2.连接服务器*/
/*2.1填充struct sockaddr_in结构体变量*/
bzero(&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(SERV_PORT); //网络字节序的端口号
#if 0
sin.sin_addr.s_addr = inet_addr(SERV_IP_ADDR);
#else
if (inet_pton(AF_INET, SERV_IP_ADDR, (void *)&sin.sin_addr) != 1)
{
perror("inet_pton");
exit(1);
}
#endif
if ((connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0))
{
perror("connect");
exit(1);
}
#if 0
/*3.读写数据*/
char buf[BUFSIZ];
while (1)
{
bzero(buf, BUFSIZ);
if (fgets(buf, BUFSIZ-1, stdin) == NULL)
{
continue;
}
write(fd, buf, strlen(buf));
if (!strncasecmp(buf, QUIT_STR, strlen(QUIT_STR))) //用户输入了quit字符
{
printf("Client is exiting!\n");
break;
}
}
#else
int ret = -1;
fd_set rset;
int maxfd = -1;
struct timeval tout;
char buf[BUFSIZ];
while (1)
{
FD_ZERO(&rset);
FD_SET(0, &rset);
FD_SET(fd, &rset);
maxfd = fd;
tout.tv_sec = 5;
tout.tv_usec = 0;
select(maxfd+1, &rset, NULL, NULL, &tout);
/*如果标准键盘上有输入,读取键盘输入,发送到网络套接字fd*/
if (FD_ISSET(0, &rset))
{
bzero(buf, BUFSIZ);
do
{
ret = read(0, buf, BUFSIZ-1);
}while(ret < 0 && EINTR == errno);
if (ret < 0)
{
perror("read");
continue;
}
if (!ret)
{
continue;
}
if (write(fd, buf, strlen(buf)) < 0)
{
perror("write() to socket");
continue;
}
if (!strncasecmp(buf, QUIT_STR, strlen(QUIT_STR))) //用户输入了quit字符
{
printf("Client is exiting!\n");
break;
}
}
/*如果服务器发送过来了数据,读取套接字数据,处理*/
if (FD_ISSET(fd, &rset))
{
bzero(buf, BUFSIZ);
do
{
ret = read(fd, buf, BUFSIZ-1);
}while(ret < 0 && EINTR == errno);
if (ret < 0)
{
perror("read from socket");
continue;
}
if (!ret) //服务器关闭
{
break;
}
printf("server said: %s\n", buf);
if (!strncasecmp(buf, QUIT_STR, strlen(QUIT_STR))) //用户输入了quit字符
{
printf("Sender Client is exiting!\n");
break;
}
}
}
#endif
/*4.关闭套接字*/
close(fd);
}