Linux:socket网络编程TCP/UDP

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

一、核心概念

  1. Socket
    网络套接字,由IP+端口号+协议唯一标识。
    在Linux中,Socket被抽象为文件描述符,可通过文件操作函数进行数据收发。

  2. 协议类型
    TCP:面向连接、可靠传输,保证数据有序、不丢失。
    UDP:无连接、不可靠传输,直接发送数据,效率高但可能丢失。

  3. 字节序:
    网络传输必须使用大端字节序,而主机可能是大端或小端,需通过 htons()ntohs() 等函数转换。

二、TCP的三次握手和四次挥手

TCP三次握手:建立连接

  1. SYN:客户端发送一个 SYN包,请求建立连接。

  2. SYN-ACK:服务器回复 SYN-ACK,表示同意建立连接。

  3. ACK:客户端再发送一个 ACK 包,连接建立完成。

TCP 四次挥手:断开连接

  1. FIN:主动方发送 FIN,表示“我不再发送数据”。

  2. ACK:被动方回复 ACK,确认收到。

  3. FIN:被动方也发送 FIN,表示“我也不再发送数据”。

  4. ACK:主动方回复 ACK,连接彻底关闭。

三、关键函数说明

函数作用常用参数
socket()创建 Socket 描述符domain(协议族,如 AF_INET)、typeSOCK_STREAM/SOCK_DGRAM
bind()绑定地址和端口Socket 描述符、sockaddr 结构体(含IP和端口)、地址长度
listen()监听 TCP 连接Socket 描述符、等待队列长度
accept()接受 TCP 连接监听 Socket 描述符、输出客户端地址、地址长度
connect()TCP 客户端连接服务器Socket 描述符、服务器sockaddr结构体、地址长度
send()/recv()TCP 收发数据Socket 描述符、数据缓冲区、长度、标志(通常为 0)
sendto()/recvfrom()UDP 收发数据比TCP多一个参数:目标或源地址结构体及长度
close()关闭 Socket 连接Socket 描述符

四、TCP通信代码实例

1.服务器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 8080
#define BUFFER_SIZE 1024

int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int addrlen = sizeof(address);
    char buffer[BUFFER_SIZE] = {0};
    const char *response = "Hello from server";

    // 1. 创建 TCP Socket
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 2. 设置地址结构
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY; 
    address.sin_port = htons(PORT);       

    // 3. 绑定Socket
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // 4. 监听连接,最大等待队列长度3
    if (listen(server_fd, 3) < 0) {
        perror("listen failed");
        exit(EXIT_FAILURE);
    }
    printf("Server listening on port %d...\n", PORT);

    // 5. 接受客户端连接
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
        perror("accept failed");
        exit(EXIT_FAILURE);
    }
    printf("Client connected\n");

    // 6. 读取客户端数据
    read(new_socket, buffer, BUFFER_SIZE);
    printf("Received from client: %s\n", buffer);

    // 7. 向客户端发送响应
    send(new_socket, response, strlen(response), 0);
    printf("Response sent\n");

    // 8. 关闭连接
    close(new_socket);
    close(server_fd);
    return 0;
}
2.客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUFFER_SIZE 1024

int main() {
    int sock = 0;
    struct sockaddr_in serv_addr;
    char buffer[BUFFER_SIZE] = {0};
    const char *message = "Hello from client";

    // 1. 创建 TCP Socket
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    // 2. 设置服务器地址
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
        perror("invalid address");
        exit(EXIT_FAILURE);
    }

    // 3. 连接服务器
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("connection failed");
        exit(EXIT_FAILURE);
    }

    // 4. 向服务器发送数据
    send(sock, message, strlen(message), 0);
    printf("Message sent\n");

    // 5. 读取服务器响应
    read(sock, buffer, BUFFER_SIZE);
    printf("Received from server: %s\n", buffer);

    // 6. 关闭连接
    close(sock);
    return 0;
}

五、UDP通信代码实例

1.服务器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 8080
#define BUFFER_SIZE 1024

int main() {
    int sock_fd;
    struct sockaddr_in serv_addr, cli_addr;
    socklen_t cli_len = sizeof(cli_addr);
    char buffer[BUFFER_SIZE] = {0};
    const char *response = "Hello from UDP server";

    // 1. 创建 UDP Socket
    if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 2. 设置服务器地址
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(PORT);

    // 3. 绑定地址和端口
    if (bind(sock_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    printf("UDP server listening on port %d...\n", PORT);

    // 4. 接收客户端数据
    int n = recvfrom(sock_fd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&cli_addr, &cli_len);
    buffer[n] = '\0';  
    printf("Received from client: %s\n", buffer);

    // 5. 向客户端发送响应
    sendto(sock_fd, response, strlen(response), 0, (struct sockaddr *)&cli_addr, cli_len);
    printf("Response sent\n");

    // 6. 关闭 Socket
    close(sock_fd);
    return 0;
}
2.客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUFFER_SIZE 1024

int main() {
    int sock_fd;
    struct sockaddr_in serv_addr;
    socklen_t serv_len = sizeof(serv_addr);
    char buffer[BUFFER_SIZE] = {0};
    const char *message = "Hello from UDP client";

    // 1. 创建 UDP Socket
    if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 2. 设置服务器地址
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);

    // 3. 向服务器发送数据
    sendto(sock_fd, message, strlen(message), 0, (struct sockaddr *)&serv_addr, serv_len);
    printf("Message sent\n");

    // 4. 接收服务器响应
    int n = recvfrom(sock_fd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&serv_addr, &serv_len);
    buffer[n] = '\0';
    printf("Received from server: %s\n", buffer);

    // 5. 关闭Socket
    close(sock_fd);
    return 0;
}

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值