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


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

    该实例摘自《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 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
    ", 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
    ");
            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
    ");
            return -1;
        }
    
        err = listen(ss, BACKLOG);
        if(err < 0){
            printf("listen error
    ");
            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
    ");
            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 数据接收机制

  • 相关阅读:
    实现可重启线程
    让别人能登陆你的mysql
    zmq消息订阅
    git备忘
    【LeetCode】数组排列问题(permutations)(附加next_permutation解析)
    【LeetCode】 数相加组合 Combination Sum
    【LeetCode】【找元素】Find First and Last Position of Element in Sorted Array
    【LeetCode】【数组归并】Merge k Sorted Lists
    【LeetCode】【动态规划】Generate Parentheses(括号匹配问题)
    【Leetcode】Remove Nth Node From End of List
  • 原文地址:https://www.cnblogs.com/happygirl-zjj/p/7120153.html
走看看 - 开发者的网上家园