linux进程间通信-套接字_套接字

套接字(Socket)

不仅可以用于同一台主机上的进程间通信,还可以用于跨网络的进程间通信。套接字可以使用不同的协议,如TCP或UDP。

套接字的基本概念:

  1. 流式套接字(Stream Sockets):提供有序、可靠、面向连接的通信服务,数据在传输过程中按字节流的方式处理,如 TCP。
  2. 数据报套接字(Datagram Sockets):提供无序、不可靠、面向数据报的通信服务,每个数据报是一个独立的、有界限的单元,如 UDP。
  3. 原始套接字(Raw Sockets):允许程序员直接处理底层的网络协议,如 ICMP。
  4. 序列套接字(Sequenced Sockets):提供有序、可靠的通信服务,但不面向字节流,每个消息都是独立的,如 SCTP。

套接字通信的关键流程:

服务端流程:

  1. 创建套接字 :使用 socket() 函数创建一个 TCP 套接字。
  2. 绑定地址 :使用 bind() 函数将套接字与特定的 IP 地址和端口号绑定。
  3. 监听连接 :使用 listen() 函数使套接字进入监听状态,等待客户端的连接请求。
  4. 接受连接 :使用 accept() 函数接受客户端的连接请求,创建一个新的通信套接字。
  5. 数据通信 :使用 send() 和 recv() 函数与客户端进行数据通信。
  6. 关闭连接 :通信结束后,使用 close() 函数关闭套接字。

客户端流程:

  1. 创建套接字 :使用 socket() 函数创建一个 TCP 套接字。
  2. 连接服务器 :使用 connect() 函数连接到服务器指定的 IP 地址和端口号。
  3. 数据通信 :使用 send() 和 recv() 函数与服务器进行数据通信。
  4. 关闭连接 :通信结束后,使用 close() 函数关闭套接字。

套接字的选项和控制:

  • 套接字选项:可以通过 setsockopt() 和 getsockopt() 系统调用来设置或获取套接字的行为。
  • 非阻塞套接字:可以通过设置套接字选项为非阻塞模式,使得 send()recv() 和 connect() 等操作不会使程序挂起。
  • 套接字状态:可以使用 select()poll() 或 epoll() 等系统调用来监控套接字的状态,如可读、可写或有错误。

套接字通信实验:

服务器端:

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

#define PORT 8080

int main() {
    int server_fd, client_fd;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_len = sizeof(client_addr);
    char buffer[1024] = {0};

    // 创建套接字
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 绑定地址
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(PORT);
    if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // 监听连接
    if (listen(server_fd, 5) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    // 接受连接
    client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len);
    if (client_fd < 0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }

    // 数据通信
    printf("Server: Connected to client\n");
    while (recv(client_fd, buffer, sizeof(buffer), 0) > 0) {
        printf("Server: Received message from client\n");
        send(client_fd, buffer, strlen(buffer), 0);
        memset(buffer, 0, sizeof(buffer));
    }

    // 关闭连接
    close(client_fd);
    close(server_fd);

    printf("Server quit\n");

    return 0;
}

客户端:

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

#define PORT 8080

int main() {
    int sock_fd;
    struct sockaddr_in server_addr;
    char buffer[1024] = {0};

    // 创建套接字
    sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (sock_fd < 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 连接服务器
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);

    if (connect(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("connect failed");
        exit(EXIT_FAILURE);
    }

    // 数据通信
    printf("Client: Connected to server\n");
    while (1) {
        memset(buffer, 0, sizeof(buffer));
        printf("Client: Enter message to send to server (or 'quit' to exit): ");
        fgets(buffer, sizeof(buffer), stdin);
        if (strncmp(buffer, "quit", 4) == 0) {
            break;
        }
        send(sock_fd, buffer, strlen(buffer), 0);
        if (recv(sock_fd, buffer, sizeof(buffer), 0) <= 0) {
            perror("recv failed");
            break;
        }
        printf("Server response: %s\n", buffer);
    }

    // 关闭连接
    close(sock_fd);

    printf("Client quit\n");

    return 0;
}

实验结果截图:

linux进程间通信-套接字_套接字_02