#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
struct timeval{
long tv_sec; / * 秒数 * /
long tv_usec; / * 微秒(百万分之一秒) * /
};
int select(int maxfd, fd_set *readset, fd_set *writeset, fd_set *exceptset, timeval *tv);
参数从前至后:最大文件描述符+1, 读文件描述符集合,写文件描述符集合,异常文件描述符集合,等待超时时间
fd_set set;
FD_ZERO(&set); /*将set清零使集合中不含任何fd*/
FD_SET(fd, &set); /*将fd加入set集合*/
FD_CLR(fd, &set); /*将fd从set集合中清除*/
FD_ISSET(fd, &set); /*测试fd是否在set集合中*/
当使用select时,1个最常见的编程错误是:忘了对最大描述字加1
忘了描述字集是值-结果参数,select返回时会将那些没准备好的bit置为0,所以如果要再次select时,一定要重新用FD_SET设置你感兴趣的描述字的对应bit
忘记重新填写timeout的值
server.c代码如下:
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/select.h>
ssize_t readn(int fd, void *buf, size_t count);
ssize_t writen(int fd, const void *buf, size_t count);
ssize_t readline(int fd, void *buf, int size);
int init_fdset(fd_set *set, int listen_socketfd,
int connect_socketfd[],int size, int *maxfd);
int deal_listen_socket(int listen_socketfd,
int connect_socketfd[], int size);
int deal_connect_socket(int connect_socketfd[], int index);
int open_listen_socket(const char *ipstr, uint16_t port);
int main()
{
int ret = -1;
char recv_buf[100];
int listen_socketfd = -1;
int connect_socketfd[100];
int temp_fd = -1;
int maxfd = -1;
int *pcnn_sd = NULL;
fd_set rset;
int i = 0;
for (i=0;
i<sizeof(connect_socketfd)/sizeof(int);
i++)
{
connect_socketfd[i] = -1;
}
listen_socketfd = open_listen_socket("127.0.0.1", 4321);
if (listen_socketfd < 0)
{
printf("open_listen_socket err\n");
return -1;
}
while (1)
{
init_fdset(&rset, listen_socketfd, connect_socketfd,
sizeof(connect_socketfd)/sizeof(int), &maxfd);
ret = select(maxfd+1, &rset, NULL, NULL, NULL);
if (ret < 0)
{
perror("select err");
return -1;
}
if (FD_ISSET(listen_socketfd, &rset))
{
deal_listen_socket(listen_socketfd, connect_socketfd,
sizeof(connect_socketfd)/sizeof(int));
}
for (i=0;
i<sizeof(connect_socketfd)/sizeof(int);
i++)
{
if (connect_socketfd[i] > 0)
{
if (FD_ISSET(connect_socketfd[i], &rset))
{
deal_connect_socket(connect_socketfd, i);
}
}
}
}
close(listen_socketfd);
return 0;
}
int init_fdset(fd_set *set, int listen_socketfd, int connect_socketfd[],
int size, int *maxfd)
{
int i = 0;
FD_ZERO(set);
FD_SET(listen_socketfd, set);
*maxfd = listen_socketfd;
for (i=0;
i<size;
i++)
{
if (connect_socketfd[i] >= 0)
{
FD_SET(connect_socketfd[i], set);
if (connect_socketfd[i] > *maxfd)
{
*maxfd = connect_socketfd[i];
}
}
}
return 0;
}
int deal_listen_socket(int listen_socketfd,
int connect_socketfd[], int size)
{
int temp_fd = -1;
int i = -1;
struct sockaddr_in client_addr;
socklen_t client_addr_len = 0;
client_addr_len = sizeof(struct sockaddr_in);
temp_fd = accept(listen_socketfd,
(struct sockaddr *)&client_addr,
&client_addr_len);
if (temp_fd < 0)
{
perror("accept err");
return -1;
}
for (i=0;
i<size;
i++)
{
if (connect_socketfd[i] < 0)
{
connect_socketfd[i] = temp_fd;
break;
}
}
return 0;
}
int deal_connect_socket(int connect_socketfd[], int index)
{
char recv_buf[100];
int ret = -1;
memset(recv_buf, 0, sizeof(recv_buf));
ret = readline(connect_socketfd[index],
recv_buf, sizeof(recv_buf));
if (ret < 0)
{
perror("readline err");
}
else if (ret == 0)
{
printf("client close\n");
close(connect_socketfd[index]);
connect_socketfd[index] = -1;
}
else
{
ret = writen(connect_socketfd[index],
recv_buf, ret);
if (ret < 0)
{
perror("writen err");
close(connect_socketfd[index]);
connect_socketfd[index] = -1;
}
}
return 0;
}
int open_listen_socket(const char *ipstr, uint16_t port)
{
int ret = -1;
int listen_sd = -1;
struct sockaddr_in server_addr;
listen_sd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_sd < 0)
{
perror("socket err");
return -1;
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
ret = inet_pton(AF_INET, ipstr,
&(server_addr.sin_addr.s_addr));
if (ret < 0)
{
perror("inet_pton err");
close(listen_sd);
return -1;
}
ret = bind(listen_sd, (struct sockaddr *)&server_addr,
sizeof(struct sockaddr_in));
if (ret < 0)
{
perror("bind err");
close(listen_sd);
return -1;
}
ret = listen(listen_sd, 6);
if (ret < 0)
{
perror("listen err");
close(listen_sd);
return -1;
}
return listen_sd;
}
ssize_t readn(int fd, void *buf, size_t count)
{
char *strtmp = NULL;
ssize_t reval = 0;
ssize_t realcount = 0;
strtmp = (char *)buf;
while (count > 0)
{
reval = read(fd, strtmp, count);
if (reval < 0)
{
if (errno == EINTR)
{
continue;
}
else
{
return -1;
}
}
else if (reval > 0)
{
count -= reval;
strtmp += reval;
realcount += reval;
continue;
}
else
{
break;
}
}
return realcount;
}
ssize_t writen(int fd, const void *buf, size_t count)
{
char *strtmp = NULL;
ssize_t reval = 0;
ssize_t realcount = 0;
strtmp = (char *)buf;
while (count > 0)
{
reval = write(fd, strtmp, count);
if (reval < 0)
{
if (errno == EINTR)
{
continue;
}
else
{
return -1;
}
}
else if (reval > 0)
{
count -= reval;
strtmp += reval;
realcount += reval;
continue;
}
else
{
break;
}
}
return realcount;
}
ssize_t readline(int fd, void *buf, int size)
{
char *strtmp = NULL;
ssize_t reval;
ssize_t realcount=0;
strtmp = (char *)buf;
while(size>1)
{
reval = read(fd, strtmp, 1);
if (reval < 0)
{
if (errno == EINTR)
{
continue;
}
else
{
return -1;
}
}
else if (reval == 0)
{
break;
}
else
{
realcount++;
size--;
if (*strtmp++ == '\n')
{
break;
}
}
}
*strtmp='\0';
return realcount;
}
client.c代码如下:
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/select.h>
ssize_t readn(int fd, void *buf, size_t count);
ssize_t writen(int fd, const void *buf, size_t count);
ssize_t readline(int fd, void *buf, int size);
void read_stdin(int socketfd);
void read_socket(int socketfd);
int open_socket(const char *ipstr, uint16_t port);
int main()
{
int socketfd = -1;
int *psocket = NULL;
int ret = -1;
fd_set rset;
socketfd = open_socket("127.0.0.1", 4321);
if (socketfd < 0)
{
return -1;
}
printf("sizeof(fd_set)*8 = %d\n", sizeof(fd_set)*8);
while (1)
{
FD_ZERO(&rset);
FD_SET(0, &rset);
FD_SET(socketfd, &rset);
ret = select(socketfd+1, &rset, NULL, NULL, NULL);
if (ret < 0)
{
perror("select err");
return -1;
}
if (FD_ISSET(0, &rset))
{
read_stdin(socketfd);
}
if (FD_ISSET(socketfd, &rset))
{
read_socket(socketfd);
}
}
return 0;
}
void read_stdin(int socketfd)
{
int ret = -1;
char send_buf[100];
memset(send_buf, 0, sizeof(send_buf));
ret = readline(0, send_buf, sizeof(send_buf));
if (ret < 0)
{
perror("readline 0 err");
return;
}
else if (ret == 0)
{
printf("readline ret = 0\n");
shutdown(socketfd, SHUT_WR);
return;
}
else
{
ret = writen(socketfd, send_buf, strlen(send_buf));
if (ret < 0)
{
perror("writen err");
return;
}
}
}
void read_socket(int socketfd)
{
char recv_buf[100];
int ret = -1;
memset(recv_buf, 0, sizeof(recv_buf));
ret = readline(socketfd, recv_buf, sizeof(recv_buf));
if (ret < 0)
{
perror("read sd err");
return;
}
else if (ret == 0)
{
printf("sever close\n");
close(socketfd);
exit(0);
}
else
{
printf("recv_buf = %s\n", recv_buf);
}
}
int open_socket(const char *ipstr, uint16_t port)
{
int ret = -1;
int socketfd = -1;
struct sockaddr_in server_addr;
socketfd = socket(AF_INET, SOCK_STREAM, 0);
if (socketfd < 0)
{
perror("socket err");
return -1;
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
ret = inet_pton(AF_INET, ipstr,
&(server_addr.sin_addr.s_addr));
if (ret < 0)
{
perror("inet_pton err");
close(socketfd);
return -1;
}
ret = connect(socketfd,
(struct sockaddr *)&server_addr,
sizeof(struct sockaddr_in));
if (ret < 0)
{
perror("connect err");
close(socketfd);
return -1;
}
return socketfd;
}
ssize_t readn(int fd, void *buf, size_t count)
{
char *strtmp = NULL;
ssize_t reval = 0;
ssize_t realcount = 0;
strtmp = (char *)buf;
while (count > 0)
{
reval = read(fd, strtmp, count);
if (reval < 0)
{
if (errno == EINTR)
{
continue;
}
else
{
return -1;
}
}
else if (reval > 0)
{
count -= reval;
strtmp += reval;
realcount += reval;
continue;
}
else
{
break;
}
}
return realcount;
}
ssize_t writen(int fd, const void *buf, size_t count)
{
char *strtmp = NULL;
ssize_t reval = 0;
ssize_t realcount = 0;
strtmp = (char *)buf;
while (count > 0)
{
reval = write(fd, strtmp, count);
if (reval < 0)
{
if (errno == EINTR)
{
continue;
}
else
{
return -1;
}
}
else if (reval > 0)
{
count -= reval;
strtmp += reval;
realcount += reval;
continue;
}
else
{
break;
}
}
return realcount;
}
ssize_t readline(int fd, void *buf, int size)
{
char *strtmp = NULL;
ssize_t reval;
ssize_t realcount=0;
strtmp = (char *)buf;
while(size>1)
{
reval = read(fd, strtmp, 1);
if (reval < 0)
{
if (errno == EINTR)
{
continue;
}
else
{
return -1;
}
}
else if (reval == 0)
{
break;
}
else
{
realcount++;
size--;
if (*strtmp == '\n' || *strtmp == '\r')
{
break;
}
strtmp++;
}
}
strtmp++; //žÃÐÐŽø'\n' or '\r'
*strtmp='\0';
return realcount;
}