linux学习笔记(29)网络编程——服务器客户端 及多进程多线程服务器

服务器代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
    int server_fd, client_fd;
    struct sockaddr_in address;
    int addrlen = sizeof(address);
    char buffer[BUFFER_SIZE] = {0};
    printf("=== TCP服务器启动 ===\n");
    1. 创建Socket文件描述符
    //AF_INET = IPv4, SOCK_STREAM = TCP, 0 = 默认协议
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd == -1) {
        perror("socket创建失败");
        exit(EXIT_FAILURE);
    }
    printf("1. Socket创建成功\n");    
     2. 设置服务器地址
    address.sin_family = AF_INET;           // IPv4
    address.sin_addr.s_addr = INADDR_ANY;   // 监听所有网卡
    address.sin_port = htons(PORT);         // 端口号,htons转换字节序
     3. 绑定Socket到地址
    if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
        perror("绑定失败");
        close(server_fd);
        exit(EXIT_FAILURE);
    }
    printf("2. 绑定端口 %d 成功\n", PORT);
     4. 开始监听连接
     5  等待连接队列的最大长度
    if (listen(server_fd, 5) < 0) {
        perror("监听失败");
        close(server_fd);
        exit(EXIT_FAILURE);
    }
    printf("3. 开始监听,等待客户端连接...\n");
     5. 接受客户端连接没人连接则阻塞
    client_fd = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen);
    if (client_fd < 0) {
        perror("接受连接失败");
        close(server_fd);
        exit(EXIT_FAILURE);
    }
    printf("4. 客户端连接成功!\n");
     6. 接收客户端数据  会阻塞
    int bytes_read = read(client_fd, buffer, BUFFER_SIZE - 1);
    if (bytes_read > 0) {
        buffer[bytes_read] = '\0';  // 添加字符串结束符
        printf("5. 收到客户端消息: %s\n", buffer);
    }
     7. 发送回复给客户端
    char* response = "你好客户端!我是服务器!";
    write(client_fd, response, strlen(response));
    printf("6. 已发送回复给客户端\n");
     8. 关闭连接
    close(client_fd);
    close(server_fd);
    printf("7. 连接关闭,服务器退出\n");
    return 0;
}

 

端口号
0~1024知名端口
1025~4096 保留端口
一般用大于4096的
 
客户端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SERVER_IP "127.0.0.1"  // 本地回环地址
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
    int sockfd;
    struct sockaddr_in serv_addr;
    char buffer[BUFFER_SIZE] = {0};
    printf("=== TCP客户端启动 ===\n");
    // 1. 创建Socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket创建失败");
        exit(EXIT_FAILURE);
    }
    printf("1. Socket创建成功\n");
    // 2. 设置服务器地址
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    // 将IP地址字符串转换为网络字节序
    if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) {
        perror("IP地址转换失败");
        close(sockfd);
        exit(EXIT_FAILURE);
    }
    printf("2. 服务器地址设置: %s:%d\n", SERVER_IP, PORT);
    // 3. 连接服务器
    if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("连接服务器失败");
        close(sockfd);
        exit(EXIT_FAILURE);
    }
    printf("3. 连接服务器成功!\n");
    // 4. 发送数据到服务器
    char* message = "你好服务器!我是客户端!";
    write(sockfd, message, strlen(message));
    printf("4. 已发送消息: %s\n", message);
    // 5. 接收服务器回复
    int bytes_read = read(sockfd, buffer, BUFFER_SIZE - 1);
    if (bytes_read > 0) {
        buffer[bytes_read] = '\0';
        printf("5. 收到服务器回复: %s\n", buffer);
    }
    // 6. 关闭连接
    close(sockfd);
    printf("6. 连接关闭,客户端退出\n");
    return 0;
}

 

 
 
多进程并发
多进程并发让服务器可以同时服务多个客户端。
 

多进程服务器

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/wait.h>
int main() {
    printf("=== 多进程服务器启动 ===\n");
    // 1. 创建"总机电话"
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    // 2. 设置电话号码
    struct sockaddr_in address;
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(8080);
    // 3. 绑定电话号码
    bind(server_fd, (struct sockaddr*)&address, sizeof(address));
    // 4. 开始等待来电
    listen(server_fd, 5);
    printf("服务器准备就绪,等待客户连接...\n");
    while (1) {  // 无限循环,持续服务
        printf("\n=== 等待新客户 ===\n");
        // 5. 接听电话(接待顾客)
        int client_fd = accept(server_fd, NULL, NULL);
        printf("有新客户连接!\n");
        // 6. 神奇的一步:创建子进程(分配服务员)
        pid_t pid = fork();
        if (pid == 0) {
            // 子进程区域(服务员的工作)
            printf("子进程 %d: 开始服务客户\n", getpid());
            // 关闭不需要的服务器socket(子进程不需要接听新电话)
            close(server_fd);
            // 与客户对话
            char buffer[1024] = {0};
            read(client_fd, buffer, sizeof(buffer));
            printf("子进程 %d: 收到客户消息: %s\n", getpid(), buffer);
            // 回复客户
            char reply[100];
            snprintf(reply, sizeof(reply), "你好!我是服务员%d", getpid());
            write(client_fd, reply, strlen(reply));
            printf("子进程 %d: 服务完成,退出\n", getpid());
            close(client_fd);
            exit(0);  // 子进程完成任务后退出
        }
        else {
            // 父进程区域(接待员的工作)
            printf("父进程: 已分配子进程 %d 服务客户\n", pid);
            close(client_fd);  // 父进程不需要与客户直接通话
        }
    }
    close(server_fd);
    return 0;
}
=== 多进程服务器启动 ===
服务器准备就绪,等待客户连接...

=== 等待新客户 ===
有新客户连接!
父进程: 已分配子进程 1234 服务客户
子进程 1234: 开始服务客户
子进程 1234: 收到客户消息: 你好服务器!我是客户5678
子进程 1234: 服务完成,退出

=== 等待新客户 ===
有新客户连接!
父进程: 已分配子进程 1235 服务客户
子进程 1235: 开始服务客户
子进程 1235: 收到客户消息: 你好服务器!我是客户5679
子进程 1235: 服务完成,退出

 

测试客户端(可以开多个终端测试)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main() {
    printf("=== 客户端启动 ===\n");
    
    // 1. 创建电话
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    
    // 2. 拨打服务器电话
    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(8080);
    inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);
    
    connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
    printf("连接到服务器成功!\n");
    
    // 3. 发送消息
    char message[100];
    snprintf(message, sizeof(message), "你好服务器!我是客户%d", getpid());
    write(sockfd, message, strlen(message));
    printf("发送: %s\n", message);
    
    // 4. 接收回复
    char buffer[1024] = {0};
    read(sockfd, buffer, sizeof(buffer));
    printf("收到回复: %s\n", buffer);
    
    // 5. 保持连接一段时间,方便观察
    printf("等待5秒后退出...\n");
    sleep(5);
    
    close(sockfd);
    printf("客户端退出\n");
    return 0;
}
=== 客户端启动 ===
连接到服务器成功!
发送: 你好服务器!我是客户5678
收到回复: 你好!我是服务员1234
等待5秒后退出...
客户端退出

 

 
多线程并发

简单的多线程并发服务器

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
// 线程参数结构
typedef struct {
    int client_fd;
} thread_arg_t;
// 线程处理函数
void* handle_client(void* arg) {
    thread_arg_t* targ = (thread_arg_t*)arg;
    int client_fd = targ->client_fd;
    // 处理客户端请求
    char buffer[100];
    read(client_fd, buffer, sizeof(buffer));
    printf("线程%lu: 收到: %s\n", pthread_self(), buffer);
    // 回复客户端
    char reply[100];
    snprintf(reply, sizeof(reply), "Hello from thread %lu", pthread_self());
    write(client_fd, reply, strlen(reply));
    close(client_fd);
    printf("线程%lu: 服务完成\n", pthread_self());
    free(targ);  // 释放线程参数内存
    return NULL;
}
int main() {
    printf("=== 多线程服务器 (端口: 8081) ===\n");    
    // 创建服务器socket
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    // 设置地址
    struct sockaddr_in address;
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(8081);
    bind(server_fd, (struct sockaddr*)&address, sizeof(address));
    listen(server_fd, 5);
    printf("等待客户端连接...\n");
    while (1) {
        // 接受客户端连接
        int client_fd = accept(server_fd, NULL, NULL);
        printf("新客户端连接\n");
        // 创建线程参数
        thread_arg_t* targ = malloc(sizeof(thread_arg_t));
        targ->client_fd = client_fd;
        // 创建新线程处理客户端
        pthread_t thread_id;
        pthread_create(&thread_id, NULL, handle_client, targ);
        pthread_detach(thread_id);  // 线程分离,自动回收资源
    }
    close(server_fd);
    return 0;
}
=== 多线程服务器 (端口: 8081) ===
等待客户端连接...
新客户端连接
线程140123456: 收到: Hello from client 5678
线程140123456: 服务完成
新客户端连接
线程140123789: 收到: Hello from client 5679
线程140123789: 服务完成

 

测试客户端(通用版)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char* argv[]) {
    if (argc != 3) {
        printf("用法: %s <IP> <端口>\n", argv[0]);
        printf("示例: %s 127.0.0.1 8080\n", argv[0]);
        return 1;
    }
    
    printf("=== 客户端启动 ===\n");
    
    // 创建socket
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    
    // 设置服务器地址
    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(atoi(argv[2]));
    inet_pton(AF_INET, argv[1], &serv_addr.sin_addr);
    
    // 连接服务器
    connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
    printf("连接到服务器 %s:%s 成功!\n", argv[1], argv[2]);
    
    // 发送消息
    char message[100];
    snprintf(message, sizeof(message), "Hello from client %d", getpid());
    write(sockfd, message, strlen(message));
    printf("发送: %s\n", message);
    
    // 接收回复
    char buffer[100] = {0};
    read(sockfd, buffer, sizeof(buffer));
    printf("收到: %s\n", buffer);
    
    // 保持连接一段时间便于观察
    sleep(2);
    
    close(sockfd);
    printf("客户端退出\n");
    return 0;
}

 

 
特性
多进程
多线程
创建方式
fork()
pthread_create()
资源开销
大(独立内存空间)
小(共享内存空间)
数据共享
困难(需要IPC)
容易(共享全局变量)
稳定性
高(进程崩溃不影响其他)
低(线程崩溃影响整个进程)
通信成本
高(进程间通信复杂)
低(直接访问共享内存)
创建速度
  • 用多进程当:需要高稳定性,任务相互独立
  • 用多线程当:需要高性能,任务间需要频繁通信

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值