int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);nfds: 是三个集合中编号最高的文件描述符,加上 1readfds/writefds/exceptfds: 可读集合/可写集合/异常集合
timeout: NULL: 永久阻塞
0: 非阻塞模式
struct timeval {
long tv_sec; /* 秒 */
long tv_usec; /* 微秒 */
};
fd_set结构体
服务端
头文件
- #ifndef _NET_H_
- #define _NET_H_
-
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- typedef struct sockaddr Addr;
- typedef struct sockaddr_in Addr_in;
- #define BACKLOG 5
- #define ErrExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while(0)
-
- void Argment(int argc, char *argv[]);
- int CreateSocket(char *argv[]);
- int DataHandle(int fd);
-
-
- #endif
-
select函数
- #include "net.h"
- #include
- #define MAX_SOCK_FD 1024
-
- int main(int argc, char *argv[])
- {
- int i, ret, fd, newfd;
- fd_set set, tmpset;
- Addr_in clientaddr;
- socklen_t clientlen = sizeof(Addr_in);
- /*检查参数,小于3个 直接退出进程*/
- Argment(argc, argv);
- /*创建已设置监听模式的套接字*/
- fd = CreateSocket(argv);
-
- FD_ZERO(&set);
- FD_ZERO(&tmpset);
- FD_SET(fd, &set);
- while(1){
- tmpset = set;
- if( (ret = select(MAX_SOCK_FD, &tmpset, NULL, NULL, NULL)) < 0)
- ErrExit("select");
- if(FD_ISSET(fd, &tmpset) ){
- /*接收客户端连接,并生成新的文件描述符*/
- if( (newfd = accept(fd, (Addr *)&clientaddr, &clientlen) ) < 0)
- perror("accept");
- printf("[%s:%d]已建立连接\n",
- inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
- FD_SET(newfd, &set);
- }else{ //处理客户端数据
- for(i = fd + 1; i < MAX_SOCK_FD; i++){
- if(FD_ISSET(i, &tmpset)){
- if( DataHandle(i) <= 0){
- if( getpeername(i, (Addr *)&clientaddr, &clientlen) )
- perror("getpeername");
- printf("[%s:%d]断开连接\n",
- inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
- FD_CLR(i, &set);
- }
- }
- }
- }
- }
- return 0;
- }
-
封装函数
- #include "net.h"
-
- void Argment(int argc, char *argv[]){
- if(argc < 3){
- fprintf(stderr, "%s
\n" , argv[0]); - exit(0);
- }
- }
- int CreateSocket(char *argv[]){
- /*创建套接字*/
- int fd = socket(AF_INET, SOCK_STREAM, 0);
- if(fd < 0)
- ErrExit("socket");
- /*允许地址快速重用*/
- int flag = 1;
- if( setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag) ) )
- perror("setsockopt");
- /*设置通信结构体*/
- Addr_in addr;
- bzero(&addr, sizeof(addr) );
- addr.sin_family = AF_INET;
- addr.sin_port = htons( atoi(argv[2]) );
- /*绑定通信结构体*/
- if( bind(fd, (Addr *)&addr, sizeof(Addr_in) ) )
- ErrExit("bind");
- /*设置套接字为监听模式*/
- if( listen(fd, BACKLOG) )
- ErrExit("listen");
- return fd;
- }
- int DataHandle(int fd){
- char buf[BUFSIZ] = {};
- Addr_in peeraddr;
- socklen_t peerlen = sizeof(Addr_in);
- if( getpeername(fd, (Addr *)&peeraddr, &peerlen) )
- perror("getpeername");
- int ret = recv(fd, buf, BUFSIZ, 0);
- if(ret < 0)
- perror("recv");
- if(ret > 0){
- printf("[%s:%d]data: %s\n",
- inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port), buf);
- }
- return ret;
- }
-