linux下socket服务端简单例,多线程,超时退出,长时间没数据就退出,让客户端有需要再重新发起连接
2023-09-14 09:07:10 时间
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;
}
相关文章
- 连接Linux服务器的客户端实现(连接linux客户端)
- Linux下的多线程编程之旅(linux多线程)
- 开启Linux 系统异步机制之旅(linux系统异步机制)
- Linux系统下实现多线程编程的方法(linux线程的实现)
- 使用Linux自定义脚本实现快速生效(linux自定义脚本)
- Linux多线程编程:一个深入的探索(linux线程详解)
- 多线程在Linux系统下的应用(多线程linux)
- 查看Linux系统硬盘数量的技巧(查看linux硬盘数量)
- Linux多线程面试:突破技术壁垒!(linux多线程面试)
- Linux下编写多线程程序:技术与挑战(linux下多线程)
- 深入理解Linux根分区系统类型(linux根分区系统类型)
- Linux中的多线程进程:实现高效率的计算(linux进程的线程)
- 客户端Linux:构建更具弹性的IT环境(ss客户端linux)
- Linux下查看文件:快速方便。(linux查看目录下文件)
- Linux捕获信号:有效解决程序的问题(linux捕获信号)
- Linux多线程调试指南实战(linux多线程调试)
- Linux系统下最佳内存条数(linux内存条数)
- Linux安装LZMA:一步一步指南(linux安装lzma)
- 解决Linux下域名访问不了的问题(linux域名不能访问)
- 学习Linux编程,从零开始撰写高效程序(linux如何编写程序)
- 学习Linux多线程:掌握多线程技术,提高程序效率(linux多线程学习)
- 数据利用Linux数据泵导入数据快速有效(linux数据泵导入)
- 源深入Linux:搭建本地Yum源(linux搭建本地yum)
- Linux读写性能测试综述(linux读写测试)
- Linux快速批量更改文件名的方法(linux批量更改文件名)
- 掌握Linux基本使用技巧:常用命令总结(linux常用的基本命令)
- Mastering Multithreaded Applications with Linux: Boost Your Programming Skills(linux多线程应用)
- Linux服务器与客户端的联动之旅(linux 服务器客户端)
- Linux系统使用者必读:锐捷客户端下载指南(linux锐捷客户端下载)
- 租用Linux服务器,获取更多稳定计算资源(租linux服务器)
- Linux多线程编程(二)