tcp_fork
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
// 定义一个类型别名,方便后续使用
typedef struct sockaddr* (SA);
// 信号处理函数,用于处理子进程结束的信号
void handle(int num)
{
// 等待子进程结束,防止产生僵尸进程
wait(NULL);
}
int main(int argc, char *argv[])
{
// 注册信号处理函数,当收到 SIGCHLD 信号时,调用 handle 函数
signal(SIGCHLD, handle);
// 创建监听套接字
int listfd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == listfd)
{
// 如果创建失败,打印错误信息并退出程序
perror(\”socket\”);
exit(1);
}
// 定义服务器地址结构体和客户端地址结构体,并初始化为 0
struct sockaddr_in ser, cli;
bzero(&ser, sizeof(ser));
bzero(&cli, sizeof(cli));
// 设置服务器地址结构体的参数
ser.sin_family = AF_INET; // 设置地址族为 IPv4
ser.sin_port = htons(50000); // 设置端口号为 50000,并转换为网络字节序
ser.sin_addr.s_addr = inet_addr(\”127.0.0.1\”); // 设置服务器 IP 地址为本地回环地址
// 设置套接字选项,允许地址和端口重用
int on = 1;
setsockopt(listfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
setsockopt(listfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
// 将监听套接字与服务器地址绑定
int ret = bind(listfd, (SA)&ser, sizeof(ser));
if (-1 == ret)
{
// 如果绑定失败,打印错误信息并退出程序
perror(\”bind\”);
exit(1);
}
// 开始监听连接请求,设置排队连接数为 3
listen(listfd, 3);
// 客户端地址结构体的长度
socklen_t len = sizeof(cli);
while (1)
{
// 接受客户端连接请求,返回通讯套接字
int conn = accept(listfd, (SA)&cli, &len);
if (-1 == conn)
{
// 如果接受连接失败,打印错误信息并继续循环
perror(\”accept\”);
// exit(1);
continue;
}
// 创建子进程
pid_t pid = fork();
if (0 == pid)
{
// 子进程执行的代码
while (1)
{
// 关闭监听套接字,因为子进程不需要它
close(listfd);
char buf[512] = {0};
// 从通讯套接字接收数据
int rd_ret = recv(conn, buf, sizeof(buf), 0);
if (rd_ret <= 0)
{
// 如果接收数据失败或客户端断开连接,打印提示信息并关闭通讯套接字,退出子进程
printf(\”cli off line\\n\”);
close(conn);
// break;
exit(1);
}
// 打印接收到的客户端数据
printf(\”cli:%s\\n\”, buf);
time_t tm;
// 获取当前时间
time(&tm);
// 将客户端数据和时间格式化后存入 buf 中
sprintf(buf, \”%s %s\”, buf, ctime(&tm));
// 将 buf 中的数据发送回客户端
send(conn, buf, strlen(buf), 0);
}
}
else if (pid > 0)
{
// 父进程执行的代码,关闭通讯套接字
close(conn);
}
else
{
// 如果 fork 失败,打印提示信息并继续循环
printf(\”fork\”);
continue;
}
}
// 关闭监听套接字
close(listfd);
return 0;
}
这段代码实现了一个简单的 TCP 服务器,它在本地回环地址的 50000 端口上监听客户端连接请求。当有客户端连接时,服务器会创建一个子进程来处理与该客户端的通信。子进程会接收客户端发送的数据,并在数据后加上当前时间后发送回客户端。同时,服务器还注册了一个信号处理函数来处理子进程结束的信号,以防止产生僵尸进程。
tcp_pthread
#include <
评论前必须登录!
注册