Linux下多线程并发服务器的简单实现
pthread_server.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include <pthread.h>
#define Max 1024
#define Error -1
static int sfd = 0;
const ushort port = 49999;
//服务器的初始化
int init_server()
{
//建立流式套接字
sfd = socket(AF_INET,SOCK_STREAM,0);
if(sfd < 0){
perror("socket");
goto SET_ERR;
}
//服务端的地址结构(ipv4)
//htons进行大小端转化
//INADDR_ANY表示任意ip地址,系统提供的宏
struct sockaddr_in server_addr = {
.sin_family = AF_INET,
.sin_port = htons(port),
.sin_addr = {
.s_addr = htonl(INADDR_ANY),
},
};
//绑定地址
if(bind(sfd,(struct sockaddr*)&server_addr,sizeof(server_addr))<0){
perror("bind");
goto SET_ERR;
}
//设置监听套接字,允许最大连接的套接字
if(listen(sfd,10) < 0){
perror("listen");
goto SET_ERR;
}
return sfd;
SET_ERR:
close(sfd);
return Error;
}
//接收客户端的数据进行处理
void *reply_client(void *arg)
{
//循环接收数据
while(1){
char buf[Max] = {0};
memset(buf,0,sizeof(buf));
//arg参数是一个void*类型,这里进行类型转换
//有的读者可能会奇怪,这里为什么写的是(int)(long)arg
//笔者这里采用的是64位的Linux系统,直接写(int)arg,看上去没有什么问题,
//进行数据类型转换,但是系统会提示一个警告,精度的丢失,在64位操作系统下面
//指针类型是8位,int类型是4位,会提示精度丢失,所以为了去掉该警告,先转换成
//long类型(64位下是8字节),如果采用的是32位操作系统,可以直接(int)arg
size_t nByte = recv((int)(long)arg,buf,sizeof(buf),0);
if(nByte < 0){
perror("recv");
return (void *)Error;
}else if(nByte == 0){
printf("the client is disconnect...\n");
close((int)(long)arg);
pthread_exit((void*)0);//退出
}else{
printf("%s\n",buf);
}
}
}
int main(int argc, const char *argv[])
{
int fd = init_server();
struct sockaddr_in clinet_addr;
int len = sizeof(clinet_addr);
printf("waiting for connect...\n");
int cfd;
while(1){
//客户端连接
cfd = accept(fd,(struct sockaddr*)&clinet_addr,&len);
if(cfd < 0){
perror("accept");
return Error;
}
printf("the client ip is %s\n",inet_ntoa(clinet_addr.sin_addr));
pthread_t tid;
//没连接一个客户端,就创建一个线程来处理客户端的数据
pthread_create(&tid,NULL,reply_client,(void *)(long)cfd);
pthread_detach(tid);//线程分离,用于回收线程
//pthread_join()也可用于线程的回收
}
return 0;
SET_ERR:
close(fd);
return Error;
}
编译执行:
gcc pthread_server.c -lpthread -o s (-lpthread表示连接线程库,这一步不能丢)
执行效果如下:(这里的客户端采用的是网络调试助手来进行模拟的,不需要自己实现)