linux下socket服务端简单例,多线程,超时退出
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
//gcc server.c -o server -lpthread
static const int g_clientTimeout_sec = 60;
static const int g_inValidfd = -1;
static int g_clientSocketfd[200];
static pthread_mutex_t g_client_mutex;
static void sig_exit(int sig)
{
fprintf(stderr, "sig_exit:%d\n",sig);
exit(0);
}
static void removeClient(int fd)
{
int i=0;
int count = sizeof (g_clientSocketfd) / sizeof (g_clientSocketfd[0]);
pthread_mutex_lock(&g_client_mutex);
for(;i<count;i++){
if(fd == g_clientSocketfd[i]){
g_clientSocketfd[i] = g_inValidfd;
break;
}
}
pthread_mutex_unlock(&g_client_mutex);
}
static void* client_thread(void* arg)
{
int iRet = 0;
int curr_flags = 0;
int clnt_sock = *((int*)arg);
char buf[100]={0};
fd_set fdset;
struct timeval timeout;
curr_flags = fcntl(clnt_sock, F_GETFL);
if (curr_flags < 0) {
perror("fcntl-F_GETFL");
}
else if (fcntl(clnt_sock, F_SETFL, curr_flags|O_NONBLOCK) != 0) {
perror("fcntl-F_SETFL O_NONBLOCK");
}
while(1){
FD_ZERO(&fdset);
FD_SET(clnt_sock, &fdset);
timeout.tv_sec = g_clientTimeout_sec;//长时间没数据就退出,让客户端有需要再重新发起连接
timeout.tv_usec = 0;
iRet = select(clnt_sock + 1, &fdset, NULL, NULL, &timeout);
if ((iRet > 0) && (FD_ISSET(clnt_sock, &fdset))) {
//read all
while(1){
memset(buf,0,sizeof (buf));
iRet = read(clnt_sock,buf,sizeof (buf));
printf("[%d][%s]\n",iRet,buf);
if(iRet < 0 && errno == EINTR){
continue;
}
if(iRet < 1){
break;
}
//todo 解析包
}
} else {
printf("read timeout.\n");
break;
}
}
removeClient(clnt_sock);
close(clnt_sock);
pthread_detach(pthread_self());
return NULL;
}
static int addClient(int fd)
{
int i=0,iRet = -1;
int count = sizeof (g_clientSocketfd) / sizeof (g_clientSocketfd[0]);
pthread_t th;
pthread_mutex_lock(&g_client_mutex);
for(;i<count;i++){
if(g_inValidfd == g_clientSocketfd[i]){
g_clientSocketfd[i] = fd;
if (pthread_create(&th, NULL, client_thread, (void*)(g_clientSocketfd+i)) != 0){
perror("创建处理线程失败:");
g_clientSocketfd[i] = g_inValidfd;
}else{
iRet = 0;
}
break;
}
}
pthread_mutex_unlock(&g_client_mutex);
return iRet;
}
int main()
{
int reuseaddr = 1;
int retval = 0;
int serv_sock = -1;
int clnt_sock = -1;
int max_client_count = 0;
socklen_t clnt_addr_size;
struct sockaddr_in serv_addr;
struct sockaddr_in clnt_addr;
(void) signal(SIGUSR1, sig_exit);
(void) signal(SIGCHLD, SIG_IGN);
(void) signal(SIGTSTP, sig_exit);
(void) signal(SIGINT, SIG_IGN);
(void) signal(SIGPIPE, SIG_IGN);
(void) signal(SIGKILL, sig_exit);
(void) signal(SIGSEGV, sig_exit);
pthread_mutex_init(&g_client_mutex, NULL);
max_client_count = sizeof (g_clientSocketfd) / sizeof (g_clientSocketfd[0]);
for(retval=0;retval<max_client_count;retval++){
g_clientSocketfd[retval] = g_inValidfd;
}
serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(serv_sock < 1){
perror("socket");
return -1;
}
retval = setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,sizeof(reuseaddr));
if (retval != 0) {
perror("setsockopt: reuseaddr");
}
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);//inet_addr("127.0.0.1");
serv_addr.sin_port = htons(6666);
retval = bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
if (retval != 0) {
perror("bind");
return -1;
}
retval = listen(serv_sock, 20);
if (retval != 0) {
perror("listen");
return -1;
}
clnt_addr_size = sizeof(clnt_addr);
while(1)
{
clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
if(-1 == addClient(clnt_sock)){
close(clnt_sock);
}
}
close(serv_sock);
pthread_mutex_destroy(&g_client_mutex);
return 0;
}