与多进程很相似,不多赘述,具体内容在多进程服务器的文章中
#include <stdio.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#define SERV_PORT 5001
#define BACKLOG 5
void* fun(void *arg);
typedef struct //自定义一种数据结构保存每个连接客户端的相关信息
{
int fd;
struct sockaddr_in addr; //存放ip
pthread_t id; //存放线程号
}SockInfo;
int main(int argc, char *argv[])
{
int rw_fd;
int fd;
int ret;
socklen_t len = sizeof(struct sockaddr);
struct sockaddr_in sin = {0};
int i = 0;
SockInfo info[32];
for(i = 0; i < sizeof(info)/sizeof(info[0]); i++)
info[i].fd = -1; //初始化为-1
//创建socket
if((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket");
exit(-1);
}
//初始化并绑定本机的ip和端口
sin.sin_family = AF_INET;
sin.sin_port = htons(SERV_PORT);
//如果端口号需要输入则转化一下
//int port = atoi(argv[1]); sin.sin_port = htons(port);
sin.sin_addr.s_addr = htonl(INADDR_ANY);
//避免出现bind error:address already in use的情况,设置端口复用
//出现以上错误的原因是断开连接后需要等待2MSL时间
int flag;
setsockopt = (fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
if((bind(fd, (struct sockaddr *)&sin, sizeof(sin))) < 0)
{
perror("bind");
exit(-1);
}
//监听socket
if(listen(fd, BACKLOG) < 0)
{
perror("listen");
exit(-1);
}
while(1)
{
//这样是为了选出未使用的最小的i,如果不这么做,如果已经连接的客户端又断开了,那他的i就无法
//被使用,通过初始化fd为-1,并在断开的时候再次设置为-1,达到重复利用的目的
for(i = 0; i < sizeof(info)/sizeof(info[0]); i++)
{
if(info[i].fd == -1)
break;
}
//主进程接收客户端请求
if((info[i].fd = accept(fd, (struct sockaddr *)&info[i].addr, &len)) < 0)
{
perror("accept");
exit(-1);
}
//创建子线程用于通信
pthread_create(&info[i].id, NULL, fun, &info[i]);
//设置线程分离,线程结束后会自动回收资源
pthread_detach(info[i].id);
if(i == 32) //数值跟创建的结构体数组的大小有关
break;
}
close(fd);
//只退出主线程,对子线程没有影响
pthread_exit(NULL);
return 0;
}
void* fun(void *arg)
{
char ip[64];
char buf[1024];
SockInfo *info = (SockInfo *)arg;
//接下来就是通信
while(1)
{
//打印客户端ip和端口号
printf("Cilent IP: %s, Port: %d\n\n",
inet_ntop(AF_INET,&info->addr.sin_addr.s_addr, ip, sizeof(ip)),
ntohs(info->addr.sin_port));
int len = read(info->fd, buf, sizeof(buf));
if(len == -1)
{
perror("read error");
pthread_exit(NULL);
}
else if(len == 0)
{
info->fd = -1;
printf("客户端已经断开连接\n");
close(info->fd);
break;
}
else
{
printf("recv client: %s\n",buf);
write(info->fd, buf, len);
}
}
return NULL;
}