网络协议栈学习(一)socket通信实例

 例子分为服务器端和客户端,客户端连接服务器后从标准输入读取输入的字符串,发送给服务器;服务器接收到字符串后,发送给服务器;服务器接收到字符串后统计字符串的长度,然后将该值传给客户端;客户端将接收到的信息打印到标准输出。

一、服务器端代码

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 8888
#define BACKLOG 2
#define LENGTH 1024

void process_conn_server(int s)
{
    int size = 0;
    char buffer[LENGTH];

    for(;;){
        size = read(s, buffer, LENGTH);

        if(size == 0)
            return;
        sprintf(buffer, "%d bytes altogether\n", size);
        write(s, buffer, strlen(buffer)+1);
    }
}
int main(int argc, char**argv)
{
    int ss, sc;
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    int err;
    pid_t pid;

    ss = socket(AF_INET, SOCK_STREAM, 0);
    if(ss < 0){
        printf("socket error\n");
        return -1;
    }

    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(PORT);

    err = bind(ss, (struct sockaddr*)&server_addr, sizeof(server_addr));
    if(err < 0){
        printf("bind error\n");
        return -1;
    }

    err = listen(ss, BACKLOG);
    if(err < 0){
        printf("listen error\n");
        return -1;
    }

    for(;;){
        int addrlen = sizeof(struct sockaddr);
        sc = accept(ss, (struct sockaddr*)&client_addr, &addrlen);
        if(sc < 0)
            continue;
        
        pid = fork();
        if(pid == 0){
            close(ss);
            process_conn_server(sc);
        }
        else
            close(sc);
    }
    return 0;
}

  为了方便处理,服务器端在接收到客户端的请求后会fork一个新的进程来处理。函数fork出来的进程集成了父进程的属性,泪如套接字描述符,在子进程和父进程中都各有一套。

  为了防止误操作,在父进程中关闭了客户端的套接字描述符,在子进程中关闭了服务器端的套接字描述符。一个进程中套接字的关闭不会造成套接字的真正关闭,只有当所有使用这些套接字的进程都关闭该套接字描述符,linux内核才释放它们。

二、客户端代码

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 8888
#define LENGTH 1024

void process_conn_client(int s)
{
    int size = 0;
    char buffer[LENGTH];

    for(;;){
        size = read(0, buffer, LENGTH);
        if(size > 0){
            write(s, buffer, size);
            size = read(s, buffer, LENGTH);
            write(1, buffer, size);
        }

    }
}
int main(int argc, char**argv)
{
    int s;
    struct sockaddr_in server_addr;
    int err;

    s = socket(AF_INET, SOCK_STREAM, 0);
    if(s < 0){
        printf("socket error\n");
        return -1;
    }

    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(PORT);

    connect(s, (struct sockaddr*)&server_addr, sizeof(struct sockaddr));
    process_conn_client(s);
    close(s);
    return 0;
}

下面将结合该例子与网络协议栈源码学习如下问题:

1、socket 本质

2、socket 数据发送机制

3、socket 数据接收机制

相关推荐
LccKyI10 分钟前
C#学习day04
经验分享·笔记·学习·c#
math_hongfan10 分钟前
鸿蒙企业级数据存储高级架构:从读写分离到冷热数据分层/归档策略/数据生命周期管理最佳实践
人工智能·学习·华为·架构·harmonyos·鸿蒙
MartinYeung514 分钟前
[论文学习]LLM智能体无法保密:多智能体系统中的隐私评估
人工智能·学习
、达西先生14 分钟前
GMR IK数学原理解读
笔记·学习·il·遥操作·模仿学习
令狐前生15 分钟前
DDD领域模型学习笔记
笔记·学习·架构
探物 AI26 分钟前
yolov6的骨干网络组件18:RepVGG,多分支进行训练,单分支进行推理(我有了SCI的主意)
网络·深度学习·yolo
LccKyI1 小时前
C#学习day05(开发福彩双色球系统附思维导图)
开发语言·学习·c#
湘美书院--湘美谈教育2 小时前
湘美书院谈探索式教育,中医药AI研究络病理论
大数据·人工智能·深度学习·学习·生活
PC2005-cloud2 小时前
Redis学习笔记:Cluster 集群读写分离实战,Lettuce + Spring Boot 从配置到验证
redis·笔记·学习
math_hongfan2 小时前
鸿蒙存储异常高级排查:文件损坏检测/数据恢复/读写失败重试/磁盘空间预警系统性根治方案
学习·华为·harmonyos·鸿蒙