多进程创建并发服务器的思想:只要有一个新的客户端连接服务器,就立刻创建一个子进程,与客户端交互
int main()
{
while(1)
{
newsockfd = accept(sockfd, NULL, NULL);
//只要accept函数,解除阻塞一次,就说明有一个新的客户端连接服务器成功,创建一个子进程与客户端交互
int ret = fork();
}
return 0;
}
#include "my.h"
//nc 192.168.31.179 6666
int main(int argc, const char *argv[])
{
int newsockfd;
char buf[100] = { 0 };//用来保存接收到的数据
//1.创建一个流式套接字
int sockfd = socket(AF_INET, SOCK_STREAM,0);
if(sockfd == -1)
{
perror("sockfd faield!!\n");
exit(-1);
}
printf("sockfd is %d\n",sockfd);
//2.绑定服务器本机的IP地址和端口号
struct sockaddr_in myaddr = { 0 };//用来保存接收端自己的IP地址和端口号
myaddr.sin_family = AF_INET;//IPv4
myaddr.sin_port = htons(6666);//将主机字节序的端口号转为网络字节序
// myaddr.sin_addr.s_addr = inet_addr("192.168.31.179");//127.0.0.1主机环回地址
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY 这个宏,可以自动获取本机的IP地址
int ret = bind(sockfd, (struct sockaddr*)&myaddr,sizeof(myaddr));
if(ret == -1)
{
perror("bind failed!!");
exit(-1);
}
//3.设置监听(允许同时连接的最大个数)
listen(sockfd, 5);
//4.阻塞等待客户端连接
//当你不想知道连接的那个客户端的IP地址和端口号的时候,可以直接将第三个和第四个参数赋值为空
//int newsockfd = accept(sockfd, NULL, NULL);
//当你想要知道连接服务器的那个客户端的IP地址和端口号的时候,需要额外定义变量保存
struct sockaddr_in clientaddr = { 0 };
int len = sizeof(clientaddr);
while(1)
{
newsockfd = accept(sockfd, (struct sockaddr*)&clientaddr, &len);//只要accept解除一次,就有一个新的客户端连接,就会执行一遍pthread_create,也就创建了一个线程
printf("newsockfd is %d\n",newsockfd);
int ret = fork();//只要fork执行一次,就产生一个子进程,与客户端交互
if(ret == -1)
{
perror("fork failed!!");
exit(-1);
}
else if(ret == 0)//说明是子进程
{
while(1)
{
//5.阻塞接收数据
ret = recv(newsockfd, buf, sizeof(buf), 0);//第四个参数0,代表阻塞接收
if(ret <= 0)//说明 客户端已经断开连接
{
printf("ret is %d\n",ret);
printf("客户端断开连接!!\n");
close(newsockfd);
exit(0);//结束这个与客户端交互的子进程
}
printf("recv is %s\n",buf);
//printf("fromCleintIP-Port %s-%d:%s\n",(char*)inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port),buf);
send(newsockfd, buf, strlen(buf)+1, 0);//回传给客户端
}
}
}
//6.关闭套接字
close(sockfd);
close(newsockfd);
return 0;
}