#include "head.h"
int init_tcp_ser(const char *ip, unsigned short port)
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == sockfd)
{
perror("fail socket");
return -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");
return -1;
}
ret = listen(sockfd, 100);
if (-1 == ret)
{
perror("fail listen");
return -1;
}
return sockfd;
}
int main(int argc, const char *argv[])
{
char buff[1024] = {0};
struct sockaddr_in cli;
socklen_t clilen = sizeof(cli);
int sockfd = init_tcp_ser("192.168.1.189", 50000);
if (-1 == sockfd)
{
return -1;
}
fd_set fds;
FD_ZERO(&fds);
FD_SET(sockfd, &fds);
int maxfd = sockfd;
fd_set tmpfds;
while (1)
{
tmpfds = fds;
int cnt = select(maxfd+1, &tmpfds, NULL, NULL, NULL);
if (cnt < 0)
{
perror("fail select");
return -1;
}
if (FD_ISSET(sockfd, &tmpfds))
{
int connfd = accept(sockfd, (struct sockaddr*)&cli, &clilen);
if (connfd < 0)
{
perror("fail accept");
continue;
}
printf("[%s %d] getline\n", inet_ntoa(cli.sin_addr), ntohs(cli.sin_port));
FD_SET(connfd, &fds);
maxfd = connfd > maxfd ? connfd : maxfd;
}
for (int i = sockfd+1; i < maxfd+1; i++)
{
if (FD_ISSET(i, &tmpfds))
{
memset(buff, 0, sizeof(buff));
ssize_t size = recv(i, buff, sizeof(buff), 0);
if (size < 0)
{
FD_CLR(i, &fds);
close(i);
perror("fail recv");
continue;
}
else if (0 == size)
{
FD_CLR(i, &fds);
close(i);
printf("cli offline\n");
continue;
}
printf("cli--->ser: %s\n", buff);
strcat(buff, "----->[ok]");
size = send(i, buff, strlen(buff), 0);
if (size < 0)
{
FD_CLR(i, &fds);
close(i);
perror("fail send");
continue;
}
}
}
}
return 0;
}
1.函数接口
(1)select
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
功能:
监听文件描述符集合
参数:
nfds:最大文件描述符个数+1
readfds:读文件描述符集合
writefds:写文件描述符集合
exceptfds:其余文件描述符集合
timeout:设定超时时间
NULL:永远等待,直到有数据发生
返回值:
成功返回产生事件的文件描述符个数
失败返回-1
2. void FD_CLR(int fd, fd_set *set);
功能:将fd从文件描述符集合中移除
3. int FD_ISSET(int fd, fd_set *set);
功能:判断fd是否仍在文件描述符集合中
4. void FD_SET(int fd, fd_set *set);
功能:将fd加入文件描述符集合
5. void FD_ZERO(fd_set *set);
功能:将文件描述符集合清0
6.select函数缺点
(1)select监听文件描述符个数上限为1024
(2)select监听的文件描述符集合在应用层,事件发时,内核数据需要传递给应用层,造成资源开销
(3)select需要手动检测产生事件的文件描述符
(4)select只能工作在水平触发模式(低速模式)