//----------------------------------------------------
//AUTHOR: lanyang123456
//DATE: 2014-10-12
//----------------------------------------------------
代码实例如下:
/*
TCP
server_v2.0
use select
API
inet_aton()
inet_ntoa()
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#define LENGTH_OF_LISTEN_QUEUE 20
#define SERVER_PORT 6666
#define MAXLINE 4096
#define MAX_FD_NUM 2
int main(int argc, char** argv)
{
int listenfd, connfd;
struct sockaddr_in servaddr;
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
char recv_buff[4096];
char response[] = "recv well done.";
int recv_len;
fd_set readfd;
int ret;
int fdset[MAX_FD_NUM] = {-1, -1};
int max_fd;
int i;
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) {
printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
fdset[0] = listenfd;
max_fd = listenfd;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERVER_PORT);
if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
if (listen(listenfd, LENGTH_OF_LISTEN_QUEUE) == -1) {
printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
printf("----------waiting for client's request---------\n");
while (1) {
/*每次调用select前,都要重置监听的描述符*/
FD_ZERO(&readfd);
for (i=0; i < MAX_FD_NUM; i++) {
if (fdset[i] != -1) {
FD_SET(fdset[i], &readfd);
}
}
ret = select(max_fd + 1, &readfd, NULL, NULL, NULL);//有数据时才返回
if (ret == -1) { //错误情况
if (errno == EINTR) {//signal interrupt
continue;
}
else {
perror("select error");
exit(0);
}
}
else if (ret) { //返回值大于0 有数据到来
if (FD_ISSET(listenfd, &readfd))
{
if((connfd = accept(listenfd, (struct sockaddr *)&client_addr, &client_addr_len)) == -1) {
printf("accept socket error: %s(errno: %d)\n",strerror(errno),errno);
continue;
}
printf("accept a new connection from client: %s\n", inet_ntoa(client_addr.sin_addr));
fdset[1] = connfd;
max_fd = connfd;
} else if (FD_ISSET(connfd, &readfd)) {
memset(recv_buff, 0, MAXLINE);
recv_len = recv(connfd, recv_buff, MAXLINE - 1, 0);
if (recv_len <= 0) {
printf("recv socket error: %s(errno: %d)\n",strerror(errno),errno);
close(connfd);
continue;
}
recv_buff[recv_len] = '\0';
printf("recv msg %d byte from client: %s\n", recv_len, recv_buff);
if (send(connfd, response, strlen(response), 0) < 0) {
printf("send socket error: %s(errno: %d)\n", strerror(errno), errno);
close(connfd);
continue;
}
//close(connfd);
//fdset[1] = -1;
//max_fd = listenfd;
}
}
else //ret 为0,超时情况
{
printf("time out\n");
//close(keybd_fd);//产生异常,查看结果
}
}
close(listenfd);
exit(0);
}
client 端可参考
http://blog.csdn.net/lanyang123456/article/details/40024327
注意的地方:
当client connect 成功建立,然后关闭sockfd。此时server端已成功接到客户端的连接,处于select阻塞状态,当客户端关闭连接时,select监控的描述符会有数据到来,select返回, 接着会调用recv, 并且recv立刻返回,返回值为0.也就是说客户端断开连接,select有事件发生,recv会立刻返回。
参考
http://blog.csdn.net/dlutbrucezhang/article/details/8577810
http://blog.csdn.net/microtong/article/details/4989902
http://blog.csdn.net/klarclm/article/details/8825930
http://www.oschina.net/code/snippet_97047_675