網絡協議棧學習(一)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\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 數據接收機制


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM