跳转到内容

Socket网络编程 ​

更新: 10/23/2026 字数: 0 字 时长: 0 分钟

socket是内核向应用层提供的一套网络编程接口,用户基于 socket 接口可开发自己的网络相关应用程序。

主要函数介绍 ​

创建套接字 ​

c
int socket(int domain, int type, int protocol);
  • domain:指定协议族,常用的有:
    • AF_INET:IPv4
    • AF_INET6:IPv6
  • type:指定套接字类型:
    • SOCK_STREAM:面向连接(TCP)
    • SOCK_DGRAM:无连接(UDP)
  • protocol:指定协议类型,通常设为 0 表示根据 domain 和 type 自动选择协议。

绑定端口 ​

c
int bind(int sockfd, struct sockaddr *addr, socklen_t addrlen);
  • sockfd:由 socket 函数返回的文件描述符。

  • addr:指向包含本地 IP 和端口号的 sockaddr 结构体。

  • addrlen:addr 结构体的大小,通常使用 sizeof(struct sockaddr_in)。

c
struct sockaddr {
    unsigned short sa_family; // 地址族(如 AF_INET)
    char sa_data[14];      // 协议地址(通常不直接使用)
};

由于系统的兼容性,一般使用 struct sockaddr_in 来替代

c
struct sockaddr_in {
    unsigned short    sin_family; // 地址族,必须为 AF_INET
    unsigned short    sin_port;   // 端口号,使用 htons() 转换
    struct in_addr    sin_addr;   // IPv4 地址,设置为 INADDR_ANY 表示可以和任何的主机通信
    unsigned char     sin_zero[8];// 填充字节,保持与 sockaddr 长度一致
};

struct in_addr {
    in_addr_t s_addr; // IPv4 地址(以网络字节序存储)
};

监听连接(TCP) ​

c
int listen(int sockfd, int backlog);
  • sockfd:套接字描述符,必须是 SOCK_STREAM 类型。
  • backlog:等待连接队列的最大长度。

接受连接(TCP) ​

c
int accept(int sockfd, struct sockaddr *addr, int *addrlen);
  • sockfd:监听套接字。
  • addr:用于接收客户端地址信息。
  • addrlen:输入输出参数,调用前设置为 addr 的大小,调用后包含实际地址大小。

发起连接(TCP 客户端) ​

c
int connect(int sockfd, struct sockaddr *addr, int addrlen);
  • sockfd:由 socket 创建的客户端套接字。
  • addr:目标服务器地址。
  • addrlen:地址结构大小。

发送与接收数据(TCP) ​

c
ssize_t send(int sockfd, void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
  • sockfd:套接字描述符。
  • buf:发送或接收数据的缓冲区。
  • len:缓冲区大小。
  • flags:通常为 0,可设为 MSG_OOB(紧急数据)、MSG_PEEK(窥视)等。

发送与接收数据(UDP) ​

c
ssize_t sendto(int sockfd, void *buf, size_t len, int flags, struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
  • sendto 中:
    • dest_addr:目标地址结构体。
    • addrlen:目标地址结构体大小,常置为sezeof(struct sockaddr)。
  • recvfrom 中:
    • src_addr:用于接收发送者地址。
    • addrlen:接收地址长度,常置为sezeof(struct sockaddr)。

TCP 编程 ​

TCP 是一种面向连接、可靠的协议,适用于传输稳定性要求高的应用。

TCP 服务器示例 ​

c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

int main() {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(12345);
    addr.sin_addr.s_addr = INADDR_ANY;

    bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
    listen(sockfd, 5);

    int client_fd = accept(sockfd, NULL, NULL);

    char buffer[1024];
    int len = recv(client_fd, buffer, sizeof(buffer), 0);
    buffer[len] = '\0';
    printf("Received: %s\n", buffer);

    send(client_fd, "Hello Client", 12, 0);
    close(client_fd);
    close(sockfd);
    return 0;
}

TCP 客户端示例 ​

c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

int main() {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(12345);
    inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);

    connect(sockfd, (struct sockaddr*)&addr, sizeof(addr));

    send(sockfd, "Hello Server", 12, 0);
    char buffer[1024];
    int len = recv(sockfd, buffer, sizeof(buffer), 0);
    buffer[len] = '\0';
    printf("Received: %s\n", buffer);

    close(sockfd);
    return 0;
}

UDP 编程 ​

UDP 是一种无连接、不保证可靠性的协议,适用于对实时性要求高的应用,如视频、语音传输。

UDP 服务器示例 ​

c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdlib.h> 

int main() {
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1) {
        perror("socket 创建失败");
        exit(EXIT_FAILURE);
    }

    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr)); 
    
    addr.sin_family = AF_INET;
    addr.sin_port = htons(12345);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
        perror("绑定端口失败");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    struct sockaddr_in client;
    socklen_t client_len = sizeof(client);
    char buffer[1024];

    while (1)
    {
        ssize_t  len = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)&client, &client_len);

        if (len == -1) {
            perror("数据接收失败");
        } else if (len == 0) {
            printf("收到空数据报\n");  // UDP 允许长度为 0 的数据报
        } else {
            buffer[len] = '\0';  // 安全终止字符串
            printf("收到消息: %s\n", buffer);
    
            //6. 发送响应(动态计算长度)
            const char *response = "Hello Client";
            ssize_t sent_bytes = sendto(sockfd, response, strlen(response),0, (struct sockaddr*)&client, client_len);
    
            if (sent_bytes == -1) {
                perror("响应发送失败");
            }
        } 
    }

    close(sockfd);
    return 0;
}

UDP 客户端示例 ​

c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

int main() {
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    struct sockaddr_in addr;
    socklen_t addrlen = sizeof(addr);

    addr.sin_family = AF_INET;
    addr.sin_port = htons(12345);
    inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);

    sendto(sockfd, "Hello Server", 12, 0, (struct sockaddr*)&addr, addrlen);

    char buffer[1024];
    int len = recvfrom(sockfd, buffer, sizeof(buffer), 0, NULL, NULL);
    buffer[len] = '\0';
    printf("Received: %s\n", buffer);

    close(sockfd);
    return 0;
}