1.
#include <stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/un.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include<unistd.h>
//看服务器性能,看服务器,进行限流
//后面用线程池来优化
void *run(void *arg)
{
int cli_fd=*(int*)arg;
char buf[4096]={};
size_t buf_size=sizeof(buf);
while(1)
{
//接收客户端数据
//int ret=read(cli_fd,buf,buf_size);
int ret=recv(cli_fd,buf,buf_size,0);
if(ret<=0||0==strcmp(buf,"quit"))
{
printf("%d客户端请求退出\n",cli_fd);
break;
}
printf("from %d revc:%s bits:%d\n",cli_fd,buf,ret);
//发送数据给客户端
//把传过来的数据拼接:return后给客户端
strcat(buf,"return");
ret=send(cli_fd,buf,strlen(buf)+1,0);
if(ret<=0)
{
printf("客户端%d退出\n",cli_fd);
break;
}
}
//关闭
close(cli_fd);
exit(0);
}
int main(int argc,const char* argv[])
{
//创建socket
int sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0)
{
perror("socket error");
exit(1);
}
//准备自己的地址通讯地址
struct sockaddr_in addr={};
addr.sin_family=AF_INET;
addr.sin_port=htons(8888);
addr.sin_addr.s_addr=inet_addr("127.0.0.1");
socklen_t addrlen=sizeof(addr);
//绑定
if(bind(sockfd,(struct sockaddr*)&addr,addrlen)<0)
{
perror("bind error");
return -1;
}
//监听
if(listen(sockfd,5)<0)
{
perror("listen error");
return -1;
}
pthread_t tid;
for(;;)
{
//等待客户端连接
struct sockaddr_in src_addr={};
//连接,src_addr来接受客户端的ip来进行通讯存到clifd
//客户端的映射clifd
//小芳讨论:结果是因为这个for太快了,导致本轮clifd还没来的及销毁,下个clifd用的还是之前的那个clifd;!!!
//解决方法一加一个usleep(1);下面已经写了 , 解决方法二看下一篇代码详解!!!!!
int clifd=accept(sockfd,(struct sockaddr*)&src_addr,&addrlen);
if(clifd<0)
{
perror("accept error");
continue;
}
//创建线程处理客户端请求
pthread_create(&tid,NULL,run,&clifd);//因为每次都是重新执行for循环,所以一直为3
//clifd共用的是同一片空间的clifd
//等待一个线程结束
usleep(1);
}
return 0;
}
2.可能会覆盖,采用下面的方案进行改进
#include <stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/un.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include<unistd.h>
//进程是线程的池子
//当前线程数量
size_t client_count=0;
//线程多了同时返回可能会有问题
typedef struct Client{
int cli_fd;
pthread_t tid;
struct sockaddr_in cli_addr;
}Client;
typedef struct sokcaddr *sp;
//看服务器性能,看服务器,进行限流
//后面用线程池来优化
void *run(void *arg)
{
//立刻保存,否则新的连接会覆盖上一次连接,导致操作的都可能都是最后一个线程
// int cli_fd=*(int*)arg;//?
//不需要保存,因为cient专门会为此客户端访问,不会修改
Client *client=(Client*)arg;
char buf[4096]={};
size_t buf_size=sizeof(buf);
while(1)
{
//接收客户端数据
//int ret=read(cli_fd,buf,buf_size);
int ret=recv(client->cli_fd,buf,buf_size,0);
if(ret<=0||0==strcmp(buf,"quit"))
{
printf("%d客户端请求退出\n",client->cli_fd);
close(client->cli_fd);
client->cli_fd=0;//表示断开
client_count--;
return NULL;
}
printf("from %d revc:%s bits:%d\n",client->cli_fd,buf,ret);
//发送数据给客户端
//把传过来的数据拼接:return后给客户端
strcat(buf,"return");
ret=send(client->cli_fd,buf,strlen(buf)+1,0);
if(ret<=0)
{
close(client->cli_fd);
client->cli_fd=0;
client_count--;
printf("客户端%d退出\n",client->cli_fd);
return NULL;
}
}
//关闭
close(client->cli_fd);
exit(0);
}
int main(int argc,const char* argv[])
{
//创建socket
int sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0)
{
perror("socket error");
exit(1);
}
//准备自己的地址通讯地址
struct sockaddr_in addr={};
addr.sin_family=AF_INET;
addr.sin_port=htons(8888);
addr.sin_addr.s_addr=inet_addr("127.0.0.1");
socklen_t addrlen=sizeof(addr);
//绑定
if(bind(sockfd,(struct sockaddr*)&addr,addrlen)<0)
{
perror("bind error");
return -1;
}
//监听
if(listen(sockfd,5)<0)
{
perror("listen error");
return -1;
}
Client*client=(Client*)calloc(50,sizeof(Client));
size_t index=0;
for(;;)
{
//找空闲的client(cli_fd为0,认为是空闲的)
while(client[index].cli_fd)
{
//若没有空闲的则等10s在继续尝试
if(client_count>=50)
{
usleep(100000);
}
index=(index+1)%50;//0-49循环
}
//从上面的循环出来,则第index个client一定空闲
//使用molloc会开辟新的套接字
//小芳讨论:上一篇提到的问题,因为上面while(client[index].cli_fd),每一个client[index]都不一样
client[index].cli_fd=accept(sockfd,(struct sockaddr*)&client[index].cli_addr,&addrlen);
if(client[index].cli_fd<0)
{
perror("accept error");
continue;
}
//创建的时候后移用不同的变量来存储
pthread_create(&client[index].tid,NULL,run,&client[index]);
//每次传的clifd都不一样,一个萝卜一个坑
client_count++;
//COLOR_BGR2GRAY
}
return 0;
}
区别参考如下:致小方的一封信