#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/select.h>
typedef struct{
int *fd; //文件描述符数组
int count; //数组元素个数
int max_count; //fd对应空间大小
}st_fd_def;
/*
将fd接收套接字描述符放入到fd数组中
*/
int add_fd(st_fd_def* p_st_fd, int fd)
{
int i = 0;
/*
校验当前文件描述符个数等于最大分配空间时
重新申请新的fd大小+3
*/
if (p_st_fd->count == p_st_fd->max_count)
{
int *p_fd = (int*)calloc(p_st_fd->max_count+3, sizeof(int));
if (p_fd == NULL)
{
printf("calloc memory error\n");
return -1;
}
memcpy(p_fd, p_st_fd->fd, sizeof(int)*p_st_fd->count);
free(p_st_fd->fd);
p_st_fd->fd = p_fd;
p_st_fd->max_count += 3;
}
p_st_fd->fd[p_st_fd->count++] = fd;
printf("fd=%d, count===%d, max_count===%d\n", fd, p_st_fd->count, p_st_fd->max_count);
return 0;
}
int get_max_fd(st_fd_def* p_st_fd, fd_set* p_fs)
{
int i = 0;
int max_fd = 0;
max_fd = p_st_fd->fd[0];
/*
* 遍历fd数组,将各元素添加到描述符集中
* 并返回数组中最大描述符
*/
for(i = 0; i<p_st_fd->count; i++)
{
FD_SET(p_st_fd->fd[i], p_fs);
if (p_st_fd->fd[i] > max_fd)
{
max_fd = p_st_fd->fd[i];
}
}
return max_fd;
}
int remove_fd(st_fd_def* p_st_fd, int fd)
{
int i = 0;
int j = 0;
/*
删除fd数组中对应元素的值
*/
for (; i<p_st_fd->count; i++)
{
if (p_st_fd->fd[i] == fd)
{
for(j = i; j<p_st_fd->count; j++)
{
p_st_fd->fd[j] = p_st_fd->fd[j+1];
if (j == p_st_fd->count-1)
{
p_st_fd->fd[j] = -1;
}
}
}
}
p_st_fd->count--;
return i;
}
int destroy_fd(st_fd_def* p_st_fd)
{
if (p_st_fd->fd != NULL)
{
free(p_st_fd->fd);
free(p_st_fd-;
}
return 0;
}
void* thread_fun(void* arg)
{
int max_fd = 0;
int index = 0;
struct timeval tv;
char szBuff[1024];
int read_len = 0;
int res = 0;
fd_set fs;
//先动态申请一个结构体大小空间
st_fd_def *p_st_fd = (st_fd_def*)arg;
if (p_st_fd == NULL)
{
printf("calloc memory error, %s,%d\n", __FUNCTION__, __LINE__);
return (void*)0;
}
//申请3个fd数组个数
p_st_fd->fd = (int*)calloc(3, sizeof(int));
if (p_st_fd->fd == NULL)
{
printf("calloc memory error, %s,%d\n", __FUNCTION__, __LINE__);
return (void*)0;
}
p_st_fd->count = 0;
p_st_fd->max_count =3;
max_fd = get_max_fd(p_st_fd, &fs);
tv.tv_sec = 2;
tv.tv_usec = 0;
FD_ZERO(&fs);
while(res = select(max_fd+1, &fs, NULL, NULL, &tv) >=0)
{
//大于0,说明有多少个读文件描述符状态发送了变化
if (res > 0)
{
//遍历文件描述符数组,根据FD_ISSET查看哪些描述符状态发生了变化
for (index = 0; index<p_st_fd->count; index++)
{
if (FD_ISSET(p_st_fd->fd[index], &fs))
{
printf("max_fd=========%d\n", max_fd);
memset(szBuff, 0x00, sizeof(szBuff));
read_len = read(p_st_fd->fd[index], szBuff, sizeof(szBuff));
if (read_len <= 0)
{
printf("read socket[%d] closed\n", p_st_fd->fd[index]);
//当读取错误或客户端断开时,从描述符集中删除指定描述符
FD_CLR(p_st_fd->fd[index], &fs);
close(p_st_fd->fd[index]);
//删除描述符数组中的指定描述符
remove_fd(p_st_fd, p_st_fd->fd[index]);
continue;
}
printf("server read socket[%d] data is [%s]\n", p_st_fd->fd[index], szBuff);
write(p_st_fd->fd[index], szBuff, strlen(szBuff));
}
}
}
//由于服务端不断在接收新的连接,所以需要重复获取最大描述符
max_fd = get_max_fd(p_st_fd, &fs);
}
}
int main(int argc, char* argv[])
{
int client_fd;
int server_fd;
int res = 0;
int opt = 1;
socklen_t clientaddr_len;
struct sockaddr_in serveraddr;
struct sockaddr_in clientaddr;
st_fd_def st;
pthread_t tid;
if (argc < 2)
{
printf("usgae: %s port\n", argv[0]);
return -1;
}
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0)
{
perror("socket error");
return -1;
}
/* 端口重复利用 */
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, (void*)&opt, sizeof(opt));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[1]));
serveraddr.sin_addr.s_addr = INADDR_ANY;
res = bind(server_fd, (struct sockaddr*)&serveraddr, sizeof(struct sockaddr));
if (res != 0)
{
perror("bind error");
return -1;
}
res = listen(server_fd, 10);
if (res != 0)
{
perror("listen error");
return -1;
}
clientaddr_len = sizeof(struct sockaddr_in);
/*
线程函数中调用select,主线程用于接收客户端请求
*/
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, NULL, thread_fun, (void*)&st);
pthread_attr_destroy(&attr);
while(1)
{
client_fd = accept(server_fd, (struct sockaddr*)&clientaddr, &clientaddr_len);
if (client_fd < 0)
{
perror("client_fd error");
return -1;
}
// 将接收的client_fd描述符放置到描述符数组中
add_fd(&st, client_fd);
}
close(server_fd);
return 0;
}
编译:gcc server_select.c -o server_select -lpthread
./server_select 8888
结果:
fd=4, count=1, max_count=3
fd=5, count=2, max_count=3
fd=6, count=3, max_count=3
fd=7, count=4, max_count=6
max_fd=7
server read socket[4] data is [aaa]
max_fd=7
server read socket[5] data is [aaa]
max_fd=7
server read socket[6] data is [aaa]
max_fd=7
server read socket[7] data is [aaa]
max_fd=7
read socket[4] closed
max_fd=7
read socket[5] closed
max_fd=7
read socket[6] closed
max_fd=7
read socket[7] closed