"TCP/IP Network Programming" reading notes--Socket type and protocol settings

Table of contents

1--Definition of agreement

2--Socket creation

2-1--Protocol Family

2-2--Socket type (Type)

3-- Implement TCP Socket under Linux

3-1--Server side

3-2--Client

3-3--Compile and run

4--Realize TCP Socket under Windows

4-1--TCP server

4-2--TCP client

4-3--Compile and run


1--Definition of agreement

        A protocol is a communication rule used in a dialogue, and when extended to the computer field, it can be organized as " necessary communication rules for dialogue between computers ". In short, a protocol is a good agreement to complete data exchange ;

2--Socket creation

#include <sys/socket.h>

int socket(int domain, int type, int protocol); 

// 创建成功返回文件描述符,创建失败返回-1;
// domain 表示 socket 中使用的协议族(Protocol Family)信息;
// type 表示 socket 数据传输的类型信息;
// protocol 表示计算机间通信中使用的协议信息(TCP、UDP);

2-1--Protocol Family

The protocol family declared in the header file sys/socket.h

        ①: PF_INET represents the IPv4 Internet protocol family;

        ②: PF_INET6 represents the IPv6  Internet protocol family;

        ③: PF_LOCAL indicates the UNIX protocol family for local communication;

        ④: PF_PACKET represents the protocol family of the underlying Socket

        ⑤: PF_IPX means IPX Novell protocol family;

        The final protocol information actually adopted by the Socket is passed through the third parameter (protocol) of the socket function, and the third parameter is determined by the first parameter within the scope of the specified protocol family;

2-2--Socket type (Type)

        The Socket type refers to the data transmission method of the Socket , which generally determines that the protocol family cannot determine the data transmission method at the same time, because there may be multiple data transmission methods in the same protocol family ;

        Two commonly used Socket types are described below:

Connection-oriented Socket: SOCK_STREAM , the characteristics are as follows:

        ① Data will not be lost during transmission;

        ② Transmit data sequentially;

        ③ There is no data boundary in the transmitted data;

A connection-oriented Socket can only be connected to another Socket with the same characteristics;

One sentence summarizes the connection-oriented Socket: reliable , sequential delivery , byte-based connection -oriented data transmission mode;

Message-oriented Socket: SOCK_DGRAM , the characteristics are as follows:

        ① Emphasize fast transmission rather than transmission order;

        ② The transmitted data may be lost or destroyed;

        ③ The transmitted data has a data boundary, which means that the number of received data should be the same as the number of transmissions;

        ④ Limit the data size of each transmission;

One sentence summarizes message-oriented Socket: Socket that is unreliable , delivered out of order , and aimed at high-speed data transmission ;

        The parameter PF_INET refers to the IPv4 network protocol family, and SOCK_STREAM refers to connection-oriented data transmission. The only protocol that meets the above two conditions is IPPPOTO_TCP, and the TCP Socket can be created in the following ways:

int tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

        Similarly, SOCK_DGRAM refers to the message-oriented data transmission method, and the only protocol that satisfies the conditions is IPPPOTO_UDP, and a UDP Socket can be created in the following ways:

int udp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);

3-- Implement TCP Socket under Linux

3-1--Server side

// gcc tcp_server.c -o tcp_server
// ./tcp_server 9190
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

void error_handling(char *message){
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

int main(int argc, char *argv[]){
    int serv_sock;
    int clnt_sock;
    struct sockaddr_in serv_addr;
    struct sockaddr_in clnt_addr;
    socklen_t clnt_addr_size;

    char message[] = "Hello World!";
    if(argc != 2){
        printf("Usage : %s <port>\n", argv[0]);
        exit(1);
    }

    serv_sock = socket(PF_INET, SOCK_STREAM, 0); // 调用 socket 函数创建socket
    if(serv_sock == -1){
        error_handling("socket() error");
    }

    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(atoi(argv[1]));

    // 调用 bind 函数分配 ip 地址和端口号
    if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1){
        error_handling("bind() error");
    }

    // 调用 listen 函数将 socket 转为可接收连接状态
    if(listen(serv_sock, 5) == -1){
        error_handling("listen() error");
    }

    clnt_addr_size = sizeof(clnt_addr);
    // 调用 accept 函数受理连接请求
    // 没有连接请求的情况下,不会有返回情况,直到有连接请求为止
    clnt_sock = accept(serv_sock, (struct sockaddr*) &clnt_addr, &clnt_addr_size);

    if(clnt_sock == -1){
        error_handling("accept() error");
    }
    // 调用 write 函数传输数据
    write(clnt_sock, message, sizeof(message));
    close(clnt_sock);
    close(serv_sock);
    return 0;
    
}

3-2--Client

// gcc tcp_client.c -o tcp_client
// ./tcp_client 127.0.0.1 9190
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

void error_handling(char *message){
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

int main(int argc, char *argv[]){
    int sock;
    struct sockaddr_in serv_addr;
    char message[30];
    int str_len;
    int idx = 0, read_len = 0;

    if(argc != 3){
        printf("Usage : %s <IP> <port>\n", argv[0]);
        exit(1);
    }

    sock = socket(PF_INET, SOCK_STREAM, 0);
    if(sock == -1){
        error_handling("socket() error");
    }

    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
    serv_addr.sin_port = htons(atoi(argv[2]));

    if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1){
        error_handling("connect() error!");
    }

    while(read_len = read(sock, &message[idx++], 1)){
        if(read_len == -1){
            error_handling("read() error!");
        }
        str_len += read_len;
    }

    printf("Message from server : %s \n", message);
    printf("Function read call count: %d \n", str_len);
    close(sock);
    return 0;
}

3-3--Compile and run

# TCP服务端
gcc tcp_server.c -o tcp_server
./tcp_server 9190

# TCP客户端
gcc tcp_client.c -o tcp_client
./tcp_client 127.0.0.1 9190

4--Realize TCP Socket under Windows

4-1--TCP server

// gcc tcp_server_win.c -o tcp_server_win -lwsock32
// tcp_server_win 9190
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>

// 打印错误信息
void ErrorHandling(char* message){
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

int main(int argc, char* argv[]){
    WSADATA wsaData;
    SOCKET hServSock, hClntSock;
    SOCKADDR_IN servAddr, clntAddr;
    
    int szClntAddr;
    char message[] = "Hello World!";
    if(argc != 2){
        printf("Usage: %s <port>\n", argv[0]);
        exit(1);
    }

    if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){ // 初始化套接字库
        ErrorHandling("WSAStartup() error!");
    }

    hServSock = socket(PF_INET, SOCK_STREAM, 0); // 创捷socket
    if(hServSock == INVALID_SOCKET){
        ErrorHandling("socket() error!");
    }

    memset(&servAddr, 0, sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servAddr.sin_port = htons(atoi(argv[1])); // 端口

    if(bind(hServSock, (SOCKADDR*) &servAddr, sizeof(servAddr)) == SOCKET_ERROR){ // 给 socket 分配 ip 地址和端口号
        ErrorHandling("bind() error!");
    }

    if(listen(hServSock, 5) == SOCKET_ERROR){ // 置于listen状态,使socket可接收客户端连接请求
        ErrorHandling("listen() error!");
    }

    szClntAddr = sizeof(clntAddr);
    hClntSock = accept(hServSock, (SOCKADDR*)&clntAddr, &szClntAddr); // 使socket受理客户端的连接请求
    if(hClntSock == INVALID_SOCKET){
        ErrorHandling("accept() error!");
    }

    send(hClntSock, message, sizeof(message), 0); // 向连接的客户端发送数据
    closesocket(hClntSock);
    closesocket(hServSock);
    WSACleanup(); // 注销初始化的套接字库
    return 0;
}

4-2--TCP client

// gcc tcp_client_win.c -o tcp_client_win -lwsock32
// tcp_client_win 127.0.0.1 9190
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>

// 打印错误信息
void ErrorHandling(char* message){
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

int main(int argc, char* argv[]){
    WSADATA wsaData;
    SOCKET hSocket;
    SOCKADDR_IN servAddr;

    char message[30];
    int strLen = 0;
    int idx = 0, readLen = 0;
    if(argc != 3){
        printf("Usage: %s <IP> <port>\n", argv[0]);
        exit(1);
    }

    if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){ // 初始化套接字库
        ErrorHandling("WSAStartup() error!"); 
    }

    hSocket = socket(PF_INET, SOCK_STREAM, 0); // 创捷面向连接的 TCP Socket
    if(hSocket == INVALID_SOCKET){
        ErrorHandling("socket() error!");
    }

    memset(&servAddr, 0, sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = inet_addr(argv[1]);
    servAddr.sin_port = htons(atoi(argv[2]));

    if(connect(hSocket, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR){ // 向服务器端发送连接请求
        ErrorHandling("connect() error!");
    }

    while(readLen = recv(hSocket, &message[idx++], 1, 0)){ // 接收服务器发来的数据
        if(readLen == -1) ErrorHandling("read() error!");
        strLen += readLen;
        if(message[idx - 1] == '\0') break; // 读取到最后一个字节
    }
    
    printf("Message from server: %s \n", message); 
    printf("Function read call count: %d \n", strLen);

    closesocket(hSocket);
    WSACleanup(); // 注销初始化的Winsock库
    return 0;
}

4-3--Compile and run

# TCP服务端
gcc tcp_server_win.c -o tcp_server_win -lwsock32
tcp_server_win 9190

# TCP客户端
gcc tcp_client_win.c -o tcp_client_win -lwsock32
tcp_client_win 127.0.0.1 9190

Guess you like

Origin blog.csdn.net/weixin_43863869/article/details/132654240