fcnt_vector_fd.h #ifndef _FCNTL_VECTOR_FD_H #define _FCNTL_VECTOR_FD_H typedef struct{ int *fd; int conter; int max_conter; }VectorFd; extern VectorFd *create_vector_fd(void); extern void destroy_vector_fd(VectorFd *vfd); extern int get_fd(VectorFd *vfd, int index); extern void remove_fd(VectorFd *vfd, int fd); extern void add_fd(VectorFd *vfd, int fd); #endif
fcntl_vector_fd.c
#include <stdlib.h> #include "fcntl_vector_fd.h" #include <stdio.h> #include <errno.h> #include <string.h> //void *memcpy(void *dest, const void *src, size_t n); static void expansion_vector(VectorFd *vfd) { if(vfd->conter >= vfd->max_conter){ int *fds = (int *)malloc(vfd->conter + 5*sizeof(int)); if(fds == NULL){ perror("expansion:"); exit(1); } memcpy(fds, vfd->fd, sizeof(int) * vfd->conter); free(vfd->fd); vfd->fd = fds; vfd->max_conter += 5; } return ; } static int indexof(VectorFd *vfd, int fd) { int index = 0; for(;index < vfd->conter; index++){ if(vfd->fd[index] == fd){ return index; } } return -1; } VectorFd *create_vector_fd(void) { VectorFd *vfd = (VectorFd *)malloc(sizeof(VectorFd)); if(vfd == NULL){ perror("create:"); exit(1); } vfd->fd = (int *)malloc(5*sizeof(int)); vfd->conter = 0; vfd->max_conter = 5; return vfd; } void destroy_vector_fd(VectorFd *vfd) { if(vfd == NULL){ perror("destroy:"); exit(1); } free(vfd->fd); free(vfd); } int get_fd(VectorFd *vfd, int index) { if(vfd == NULL){ perror("get:"); exit(1); } if(index < 0 || index > vfd->conter -1){ return -1; } return vfd->fd[index]; } void remove_fd(VectorFd *vfd, int fd) { if(vfd == NULL){ perror("remove:"); exit(1); } int index = indexof(vfd, fd); if(index < 0){ return ; } for(;index < vfd->conter; index++){ vfd->fd[index] = vfd->fd[index +1]; } vfd->conter--; } void add_fd(VectorFd *vfd, int fd) { if(vfd == NULL){ perror("add:"); exit(1); } expansion_vector(vfd);//扩容 vfd->fd[vfd->conter] = fd; vfd->conter++; return ; }
//tcp_fcntl.c #include <signal.h> #include <stdio.h> #include <errno.h> #include <unistd.h> #include <fcntl.h> #include <stdlib.h> #include <time.h> #include <pthread.h> #include <string.h> #include <sys/wait.h> #include <arpa/inet.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include "fcntl_vector_fd.h" //int socket(int domain, int type, int protocol); //typedef void (*sighandler_t)(int); //sighandler_t signal(int signum, sighandler_t handler); //void perror(const char *s); VectorFd *vfd = NULL; int socket_fd; void sig_fun(int signo) { if(signo == SIGINT){ write(STDOUT_FILENO, "signal SIGINT", 15); destroy_vector_fd(vfd); close(socket_fd); exit(1); } } static void out_fd(struct sockaddr_in *addr;) { int port = ntohs(addr->sin_port); char ip[16]; if(inet_ntop(AF_INET, &addr->sin_addr.s_addr, ip ,16) == NULL){ perror("out_addr:"); } write(STDOUT_FILENO, ip, 16); write(STDOUT_FILENO, itoa(port), 5); return ; } //如果客户端往socket中写了数据,子线程在遍历fd时,如果能读到数据,那就将数据作相应的处理,如果读不到将不会阻塞,直接返回 void do_service(int fd) { char buffer[512]; /*相当于不完整管道 *如果服务器从socket中读取到的数据为0,说明客户端关闭了socket或客户端已经挂掉了(服务器读一个写端关闭了的socket) *如果服务器往读端(客户端)关闭了的socket中写数据,将会产生一个SIGPIPE的信号,并且errorno被设置为EPIPE(服务器写一个读端关闭了的socket) */ memset(buffer, 0, sizeof(buffer)); //采用非阻塞的read,若读不到数据就直接放回。直接服务于下一个客户端,因此不用判断size小于0的情况 size_t size = read(fd, buffer, sizeof(buffer)); if(size == 0){ write(STDOUT_FILENO, "client wtrite closed!", 25); remove_fd(vfd, fd); close(fd); break; }else if(size > 0){ write(STDOUT_FILENO, buffer, sizeof(buffer)); write(STDOUT_FILENO, "\n", 1); if(write(fd, buffer, sizeof(buffer)) <0 ){ if(errno == EPIPE){ write(STDOUT_FILENO, "client read closed!", 25); remove_fd(vfd, fd); close(fd); break; } perror("write:"); } } } void *th_fun(void *arg) { while(1){ int i = 0; for(i = 0; i < vfd->conter; i++){ do_service(get_fd(vfd, i)); } } return (void *)0; } int main(int argc,char *argv[]) { if(argc <2){ perror("argc<2:"); exit(1); } if(signal(SIGINT,sig_fun) == SIG_ERR){ perror("signal:"); exit(1); } /* *1. 创建socket */ if((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ perror("socket:"); exit(1); } /* *2.绑定IP地址和端口号 *int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen); */ struct sockaddr_in serviceaddr; memset(&serviceaddr, 0, sizeof(serviceaddr)); serviceaddr.sin_family = AF_INET; serviceaddr.sin_port = htons(atoi(argv[1])); serviceaddr.sin_addr.s_addr = INADDR_ANY;//一台服务器上可能有多块网卡(多个IP地址) //这个宏是响应本机所有网卡(IP地址)上连接的客户端请求 if(bind(socket_fd, (struct sockaddr *)&serviceaddr, sizeof(serviceaddr)) < 0){ perror("bind:"); exit(1); }; /* *3.监听绑定的端口 *通知系统去监听来自客户端的连接请求 *(将监听到的客户端连接请求放置到对应的队列中) *第二个参数:指定队列的长度 */ if(listen(socket_fd, 10) < 0){ perror("listen:"); exit(1); } //创建动态数组 vfd = create_vector_fd(); pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); pthread_t t; /* *5.创建子线程循环遍历动态数组 *int pthread_create(pthread_t *thread, const pthread_attr_t *attr, * void *(*start_routine) (void *), void *arg); */ if(pthread_create(&t, &attr, th_fun, (void *)0) != 0){ perror("pthread_create"); exit(1); } pthread_attr_destroy(&attr); /* *4.调用accept函数从队列中获得一个客户端的连接请求 *并返回一个新的socket描述符,这个描述符和和客户端 *的连接请求对应,即这个描述符和某个客户端对应 *如果没有客户端连接,调用此函数会阻塞,直到获得一个客户端的连接 *第二个参数:客户端的地址信息 */ struct sockaddr_in clientaddr; socklen_t length = sizeof(clientaddr); while(1){ int fd = accept(socket_fd, (struct sockaddr *)&clientaddr, &length); if(fd < 0){ perror("accept:"); continue; } out_addr(&clientaddr); //将套接字描述符设置为非阻塞的读写 int flags = fcntl(fd, F_GETFL, 0); if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0){ perror("fcntl:"); exit(1); } add_fd(vfd, fd); } return 0; }