思路:循环等待连接,连接成功后创建一个子线程处理该连接的数据通信,然后主线程继续等待连接。
socket接口封装:
#include "wrap.h"
#include
#include
#include
void sys_err(const char *ch)
{
perror(ch);
exit(1);
}
int Socket(int domain, int type, int protocol)
{
//创建socket
int ret = socket(domain,type,protocol);
if(ret == -1)
{
sys_err("socket error");
}
return ret;
}
int Setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen)
{
int ret = setsockopt(sockfd,level,optname,optval,optlen);
if(ret == -1)
{
sys_err("setsockopt error");
}
return ret;
}
int Bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen)
{
//绑定ip地址和端口
int ret = bind(sockfd,addr,addrlen);
if(ret == -1)
{
sys_err("socket bind error");
}
return ret;
}
int Listen(int sockfd, int backlog)
{
//设置监听上限值
int ret = listen(sockfd,backlog);
if(ret == -1)
{
sys_err("socket listen error");
}
return ret;
}
int Accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
{
int fdc = 0;
again:
//监听客户端连接
fdc = accept(sockfd,addr,addrlen);
if (fdc == -1)
{
if (errno == ECONNABORTED || errno == EINTR)
{
goto again;
}else
{
sys_err("socket accept error");
}
}
return fdc;
}
int Connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen)
{
int ret = 0;
ret = connect(sockfd,addr,addrlen);
if(ret == -1)
{
sys_err("connect error");
}
return ret;
}
int Close(int fd)
{
int ret = close(fd);
if(ret == -1)
{
sys_err("close error");
}
return ret;
}
服务器端代码:
#include "wrap.h"
#include
#include
#include
#include //toupper
#include
#include //inet_ntop
#include //bzero
#define PORT 8888
struct fdc_info
{
struct sockaddr_in addr;
int fdc;
};
void* dowork(void *arg)//线程函数
{
struct fdc_info* info = (struct fdc_info*)arg;
char clit_ip[1024];
char buf[BUFSIZ];
bzero(buf,sizeof(char)*BUFSIZ);
printf("client ip:%s,port:%d\n",
inet_ntop(AF_INET,&info->addr.sin_addr.s_addr,clit_ip,1024),
ntohs(info->addr.sin_port));
while(1)
{
int ret = read(info->fdc,buf,sizeof(buf));
if(ret == 0)
{
printf("client %d exit...\n",ntohs(info->addr.sin_port));
break;
}
write(STDOUT_FILENO,buf,ret);
for(int i=0;i<ret;++i)
{
buf[i] = toupper(buf[i]);
}
write(info->fdc,buf,ret);
}
Close(info->fdc);
return (void*)0;//pthread_exit();
}
void server_thread()
{
int fds = 0;
//int fdc = 0;
struct sockaddr_in serv_addr,clit_addr;
socklen_t clit_addr_len;
struct fdc_info fdis[256];
bzero(&serv_addr,sizeof(serv_addr));
bzero(&clit_addr,sizeof(clit_addr));
bzero(&fds,sizeof(struct fdc_info)*256);
clit_addr_len = sizeof(clit_addr);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
fds = Socket(AF_INET,SOCK_STREAM,0);
int opt = 1;//设置端口复用
Setsockopt(fds,SOL_SOCKET,SO_REUSEADDR,(void*)&opt,sizeof(opt));
Bind(fds,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
Listen(fds,128);
int i = 0;
while (i<256)
{
int fdc = Accept(fds,(struct sockaddr*)&clit_addr,&clit_addr_len);
fdis[i].addr = clit_addr;
fdis[i].fdc = fdc;
pthread_t pd;
pthread_create(&pd,NULL,dowork,&fdis[i]);
pthread_detach(pd);//分离线程
++i;
}
Close(fds);
}
int main(int args,char *argc[])
{
server_thread();
return 0;
}
测试:
可以开启多个终端使用nc 127.0.0.1 8888
命令创建连接进行测试