Socket编程是网络编程的基础,它允许两个程序在不同的主机上进行通信。无论是构建简单的客户端-服务器应用,还是复杂的分布式系统,Socket编程都是不可或缺的技能。本文将带你从Socket编程的基础概念开始,逐步深入,最终通过实战案例分析,帮助你轻松掌握Socket编程。

Socket编程基础

什么是Socket?

Socket是一种特殊的接口,它允许两个程序通过网络进行通信。在TCP/IP网络中,Socket被广泛使用。

Socket的组成

  • IP地址:确定通信双方的网络位置。
  • 端口号:确定通信双方的应用程序。

Socket类型

  • TCP Socket:提供可靠的、面向连接的服务。
  • UDP Socket:提供不可靠的、无连接的服务。

Socket编程步骤

创建Socket

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

连接Socket

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

发送数据

int send(int sockfd, const void *buf, size_t len, int flags);

接收数据

int recv(int sockfd, void *buf, size_t len, int flags);

关闭Socket

int close(int sockfd);

实战案例分析

客户端-服务器模型

服务器端

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

int main() {
    int server_fd, client_fd;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_addr_len = sizeof(client_addr);

    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(8080);

    if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("bind");
        exit(EXIT_FAILURE);
    }

    listen(server_fd, 10);

    client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_addr_len);
    if (client_fd == -1) {
        perror("accept");
        exit(EXIT_FAILURE);
    }

    char buffer[1024];
    int n = read(client_fd, buffer, sizeof(buffer));
    if (n > 0) {
        printf("Received: %s\n", buffer);
    }

    close(client_fd);
    close(server_fd);
    return 0;
}

客户端

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

int main() {
    int client_fd;
    struct sockaddr_in server_addr;
    char buffer[1024];

    client_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (client_fd == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    server_addr.sin_port = htons(8080);

    if (connect(client_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("connect");
        exit(EXIT_FAILURE);
    }

    strcpy(buffer, "Hello, Server!");
    write(client_fd, buffer, strlen(buffer));

    close(client_fd);
    return 0;
}

多线程Socket编程

服务器端

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

void *handle_client(void *arg) {
    int client_fd = *(int *)arg;
    char buffer[1024];
    int n = read(client_fd, buffer, sizeof(buffer));
    if (n > 0) {
        printf("Received: %s\n", buffer);
    }
    close(client_fd);
    free(arg);
    return NULL;
}

int main() {
    int server_fd, client_fd;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_addr_len = sizeof(client_addr);
    pthread_t thread_id;

    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(8080);

    if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("bind");
        exit(EXIT_FAILURE);
    }

    listen(server_fd, 10);

    while (1) {
        client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_addr_len);
        if (client_fd == -1) {
            perror("accept");
            continue;
        }

        int *client_fd_ptr = malloc(sizeof(int));
        *client_fd_ptr = client_fd;
        pthread_create(&thread_id, NULL, handle_client, client_fd_ptr);
    }

    close(server_fd);
    return 0;
}

客户端

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

int main() {
    int client_fd;
    struct sockaddr_in server_addr;
    char buffer[1024];

    client_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (client_fd == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    server_addr.sin_port = htons(8080);

    if (connect(client_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("connect");
        exit(EXIT_FAILURE);
    }

    strcpy(buffer, "Hello, Server!");
    write(client_fd, buffer, strlen(buffer));

    close(client_fd);
    return 0;
}

通过以上实战案例分析,相信你已经对Socket编程有了更深入的了解。只要多加练习,你一定能轻松掌握Socket编程!