#include
<stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#define SRV_PORT 12345
#define LISTEN_QUEUE 20
#define CONN_MAX 1024 /* 存放已连接的客户端描述符 */
int conn[CONN_MAX]; /* 当前已连接客户端的总数 */
int conn_amount;
int init_socket_tcp(unsigned short
port, int backlog);
void active_keepalive(int sockfd);
void set_keepalive_params(int sockfd, int idle, int
count, int
intvl);
static int firstclient = 1;
int main(int
argc, char *argv[])
{
int sockfd, cltfd = -1;
struct sockaddr_in clt_addr;
socklen_t addrlen;
int i, n;
char buf[1024];
int len;
int maxfd;
fd_set readfds;
sockfd = init_socket_tcp(SRV_PORT, LISTEN_QUEUE);
if (sockfd <
0) {
perror("init socket failed!");
exit(EXIT_FAILURE);
}
for (i =
0; i < CONN_MAX; i++) {
conn[i] = -1;
}
maxfd = sockfd;
conn_amount = 0;
while (1) {
FD_ZERO(&readfds);
FD_SET(sockfd, &readfds);
for (i = 0; i < CONN_MAX; i++) {
if (conn[i] != -1) {
FD_SET(conn[i], &readfds);
if (conn[i] > maxfd)
maxfd =
conn[i];
}
}
printf("start select............\n");
if ((n = select(maxfd + 1, &readfds, NULL, NULL, NULL)) < 0) {
perror("select faield");
continue;
}
for (i = 0; i < CONN_MAX; i++) {
if ((conn[i] != -1) && FD_ISSET(conn[i], &readfds)) {
len = read(conn[i], buf, sizeof(buf) - 1);
if (len < 0) {
if (errno == EINTR) {
printf("errno == EINTR\n");
continue;
}
if (errno == ETIMEDOUT)
printf("ETIMEDOUT..............., client: %d\n", i + 1);
perror("read error");
close(conn[i]);
conn[i] = -1;
conn_amount--;
} else if (len == 0) {
printf("client close socket.\n");
close(conn[i]);
conn[i] = -1;
conn_amount--;
} else
printf("read from client: %s\n", buf);
}
} /* for (i = 0; i < CONN_MAX; i++)*/
if (FD_ISSET(sockfd,
&readfds)) {
addrlen = sizeof(struct sockaddr_in);
cltfd = accept(sockfd, (struct sockaddr
*)&clt_addr, &addrlen);
if (cltfd < 0) {
perror("accept failed");
continue;
}
if (conn_amount < CONN_MAX) {
conn_amount++;
printf("*********** conn_amount = %d\n", conn_amount);
/* set
tcp_keepalive_* options */
/* 设置第一个客户端socket keepalive 属性 */
if (firstclient) { /* 开启 keepalive 选项 */
active_keepalive(cltfd);
/* 设置 keepalive 相关参数 */
set_keepalive_params(cltfd, 60, 3, 2);
firstclient =
0;
} else { /* 设置其他客户端socket keepalive 属性 */ /* 开启 keepalive 选项 */ active_keepalive(cltfd); /* 设置 keepalive 相关参数 */
set_keepalive_params(cltfd, 20, 3, 5);
}
for (i = 0; i < CONN_MAX; i++) {
if (conn[i] == -1) {
conn[i] = cltfd;
break;
}
}
} else { /* 到达 CONN_MAX后,不处理其他客户端连接请求 */
printf("max connection arrived, I will close the client socket!\n");
close(cltfd);
}
}
} /* while (1) */
close(sockfd);
exit(EXIT_SUCCESS);
}
int init_socket_tcp(unsigned short
port, int backlog)
{
int sockfd;
struct sockaddr_in srv_addr;
socklen_t addrlen;
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd <
0) {
perror("create socket failed!");
return -1;
}
addrlen = sizeof(struct sockaddr_in);
memset(&srv_addr,
0, sizeof(struct sockaddr_in));
srv_addr.sin_family = AF_INET;
srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
srv_addr.sin_port = htons(port);
int reuse = 1;
if (setsockopt(sockfd, SOL_SOCKET,
SO_REUSEADDR, &reuse, sizeof(int)) < 0) {
perror("setsockopt SO_REUSEADDR");
close(sockfd);
return -1;
}
if (bind(sockfd, (struct sockaddr *)&srv_addr,
addrlen) < 0) {
perror("bind errror");
close(sockfd);
return -1;
}
if (listen(sockfd, backlog)
< 0) {
perror("listen error");
close(sockfd);
return -1;
}
return sockfd;
}
void active_keepalive(int sockfd)
{
int optval;
socklen_t optlen = sizeof(optval);
/* check the status for the
keepalive option */
if (getsockopt(sockfd, SOL_SOCKET,
SO_KEEPALIVE, &optval, &optlen) < 0) {
perror("getsockopt SO_KEEPALIVE failed");
close(sockfd);
exit(EXIT_FAILURE);
}
printf("SO_KEEPALIVE is %s\n",
optval ? "ON" : "OFF");
/* set the option active */
optval = 1;
optlen = sizeof(optval);
if (setsockopt(sockfd, SOL_SOCKET,
SO_KEEPALIVE, &optval, optlen)
< 0) {
printf("setsockopt SO_KEEPALIVE failed,reason: %m\n");
close(sockfd);
exit(EXIT_FAILURE);
}
printf("SO_KEEPALIVE on socket\n");
/* check the status again */
if (getsockopt(sockfd, SOL_SOCKET,
SO_KEEPALIVE, &optval, &optlen) < 0) {
perror("getsockopt SO_KEEPALIVE again failed");
close(sockfd);
exit(EXIT_FAILURE);
}
printf("SO_KEEPALIVE is %s\n",
(optval ? "ON"
: "OFF"));
}
void set_keepalive_params(int sockfd, int idle, int
count, int
intvl)
{
int keepalive_time = idle;
int keepalive_probes = count;
int keepalive_intvl = intvl;
if (setsockopt(sockfd, SOL_TCP,
TCP_KEEPIDLE, &keepalive_time, sizeof(int)) < 0) {
perror("TCP_KEEPIDLE failed");
return;
}
if (setsockopt(sockfd, SOL_TCP,
TCP_KEEPCNT, &keepalive_probes, sizeof(int)) < 0) {
perror("TCP_KEEPCNT failed");
return;
}
if (setsockopt(sockfd, SOL_TCP,
TCP_KEEPINTVL, &keepalive_intvl, sizeof(int)) < 0) {
perror("TCP_KEEPINTVL failed");
return;
}
return;
} |