使用进程完成TCP服务器
大致步骤为:
- 创建套接字
- 设置端口复用
- 绑定
- 监听
- 返回当前连接套接字
- 接收,发送消息
- 关闭套接字
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
//创建TCP套接字
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd > 0)
{
printf("socked = %d\n",sockfd);
}
else
{
printf("创建失败\n");
}
//设置端口频复用
//此端口在同一时刻可被多个进程使用
int yes = 1;
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(void *)&yes,sizeof(yes));
//绑定地址结构体
struct sockaddr_in my_addr;
my_addr.sin_family = AF_INET; //IPv4
my_addr.sin_port = htonl(INADDR_ANY);//获取自身的ip作为服务器的ip
bind(sockfd,(struct sockaddr *)&my_addr,sizeof(my_addr));
//监听函数
//作用是监测当前有多少服务器连接,并将其放入队列中,后面的20代表队列最多能够同时有20个客户端连接
listen(sockfd,20);
while(1)
{
//建立连接
struct sockaddr_in cli_addr;
socklen_t cli_len = sizeof(cli_addr);
//拿到队列最前的客服端,并且创建一个新的套接字
int new_sockfd = accept(sockfd,(struct sockaddr *)&cli_addr,&cli_len);
//每拿到一个套接字,就创建一个子进程,从而达到多个客服端可以同时连接TCP客服端
//需要注意的是:创建的new_sockfd父进程也有,所以需要在父进程中关闭
pid_t pid = fork();
if(pid < 0)
{
perror("fork");
}
else if(pid == 0)
{
//子进程
// 在子进程中,不需要监听了,所以可以将其关闭
close(sockfd);//关闭监听套接字
char des_ip[16]="";
inet_ntop(AF_INET,(void *)&cli_addr.sin_addr.s_addr,des_ip,16);
printf("%s连接上了\n",des_ip);//打印是哪一个客户端连接
while(1)
{
//接收客户端数据
char buf[512]="";
ssize_t j = recv(new_sockfd,buf,sizeof(buf),0);
printf("len = %ld:text = %s\n",j,buf);
//判断消息是否为空
if(j==0)
{
break;
}
//此处完成”学人说话的功能“,根据自己需要进行修改
send(new_sockfd,buf,j,0);
}
close(new_sockfd);
exit(0);
}
else
{
//父进程
close(new_sockfd);
}
}
close(sockfd);
return 0;
}