//简单的高并发服务器端,实现多个客户端的连接与数据处理(聊天)
//TCP服务器端程序
//1.新连接的描述符会覆盖,因此需要一个数组保存
//2.将监听socket描述符添加到数组中
//3.定义一个select可读时间描述符
//4.将数组中可用的描述符全添加到集合中,并选择出最大的描述符
//5.定义一个select等待的超时时间
//6.select开始监控描述符的状态改变
// 1.出错返回
// 2.超时返回
// 3.代表有对象可读,但是我们不知道哪一个描述符可读
// 但是select返回之前干了一件事,将没有就绪的描述符从集合中移除
// 意味着现在集合中存在的描述符都是就绪的描述符
// 4.现在判断数组中的哪一个描述符还继续在集合中,如何在,就代表这个描述符是就绪状态的
// 1.如果这个就绪的描述符是监听描述符,代表有新连接,接收连接
// 2.如果不是,代表有数据到来,接收数据
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/select.h>
int main(int argc, char *argv[])
{
if(argc != 3) {
printf("Usage : ./a.out ip port\n");
}
//多个描述符,需要一个数组
int lis_fd, cli_fd;
int i, ret;
socklen_t len;
struct sockaddr_in lis_addr;
struct sockaddr_in cli_addr;
int fd_list[1024];
struct timeval tv;
tv.tv_sec = 3;
tv.tv_usec = 0;
fd_set readfds;
lis_fd = socket(AF_INET, SOCK_STREAM, 0);
if(lis_fd < 0) {
perror("socket error");
return -1;
}
lis_addr.sin_family = AF_INET;
lis_addr.sin_port = htons(atoi(argv[2]));
lis_addr.sin_addr.s_addr = inet_addr(argv[1]);
len = sizeof(struct sockaddr_in);
ret = bind(lis_fd, (struct sockaddr*)&lis_addr, len);
if(ret < 0) {
perror("serv bind");
return -1;
}
if(listen(lis_fd, 5) < 0) {
perror("listen");
return -1;
}
for(i = 0; i < 1024; i++) {
fd_list[i] = -1;
}
fd_list[0] = lis_fd;
int max_fd = lis_fd;
while(1) {
//清空集合
FD_ZERO(&readfds);
//将所有的fd都添加到集合当中
for(i = 0; i < 1024; i++) {
if(fd_list[i] != -1) {
FD_SET(fd_list[i], &readfds);
FD_SET(fd_list[i], &readfds);
}
//从所有的描述符中找到最大的描述符
if(fd_list[i] > max_fd) {
max_fd = fd_list[i];
}
}
//select 开始监控描述符集合中是否就绪
tv.tv_sec = 3;
tv.tv_usec = 0;
ret = select(max_fd + 1, &readfds, NULL, NULL, &tv);
if(ret < 0) {
perror("select error");
continue;
} else if(ret == 0) {
printf("timeout\n");
continue;
}
//走到这一步代表有描述符就绪(有数据到来), 但是不知道到底是哪一个描述符
//因此需要循环去判断fd列表中哪一个可读
for(i = 0; i < 1024; i++) {
if(fd_list[i] < 0) continue;
//判断哪个描述符就绪了
if(FD_ISSET(fd_list[i], &readfds)) {
//如果就绪的描述符是监听描述符就要接受
if(fd_list[i] == lis_fd) {
cli_fd = accept(lis_fd, (struct sockaddr*)&cli_fd, &len);
if(cli_fd < 0) {
continue;
}
for(i = 0; i < 1024; i++) {
if(fd_list[i] == -1) {
fd_list[i] = cli_fd;
break;
}
}
} else {
//如果就绪的描述符不是监听描述符,代表有客户端连接的数据
char buff[1024] = {0};
ret = recv(fd_list[i] , buff, 1023, 0);
if(ret <= 0) {
close(fd_list[i]);
fd_list[i] = -1;
}
printf("client say : %s\n", buff);
send(fd_list[i], "what fuck!!!\n", 12, 0);
}
}
}
}
return 0;
}
Linux下的http高并发服务器
猜你喜欢
转载自blog.csdn.net/IronMan240/article/details/81779436
今日推荐
周排行