linux socket怎么使用

发布时间:2022-02-24 16:27:24 作者:iii
来源:亿速云 阅读:228

Linux Socket 怎么使用

目录

  1. 引言
  2. Socket 基础
  3. Socket 编程基础
  4. TCP Socket 编程
  5. UDP Socket 编程
  6. 高级 Socket 编程
  7. Socket 编程中的常见问题
  8. Socket 编程实例
  9. 总结

引言

在网络编程中,Socket 是一个非常重要的概念。它允许不同计算机之间的进程进行通信,是实现网络通信的基础。Linux 广泛使用的操作系统,提供了丰富的 Socket 编程接口。本文将详细介绍如何在 Linux 中使用 Socket 进行网络编程。

Socket 基础

2.1 什么是 Socket

Socket 是网络通信的端点,它允许不同计算机之间的进程进行通信。Socket 可以看作是网络通信的接口,通过它,应用程序可以发送和接收数据。

2.2 Socket 的类型

在 Linux 中,Socket 主要有以下几种类型:

2.3 Socket 的地址结构

在 Socket 编程中,地址结构用于表示网络地址。常见的地址结构包括:

Socket 编程基础

3.1 创建 Socket

在 Linux 中,可以使用 socket() 函数创建一个 Socket。该函数的原型如下:

#include <sys/types.h>
#include <sys/socket.h>

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

3.2 绑定 Socket

创建 Socket 后,通常需要将其绑定到一个本地地址和端口上。可以使用 bind() 函数来实现:

#include <sys/types.h>
#include <sys/socket.h>

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

3.3 监听连接

对于流式 Socket(如 TCP),服务器需要监听来自客户端的连接请求。可以使用 listen() 函数来实现:

#include <sys/types.h>
#include <sys/socket.h>

int listen(int sockfd, int backlog);

3.4 接受连接

当有客户端连接请求到达时,服务器可以使用 accept() 函数接受连接:

#include <sys/types.h>
#include <sys/socket.h>

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

3.5 连接服务器

客户端可以使用 connect() 函数连接到服务器:

#include <sys/types.h>
#include <sys/socket.h>

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

3.6 发送和接收数据

在建立连接后,可以使用 send()recv() 函数发送和接收数据:

#include <sys/types.h>
#include <sys/socket.h>

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

3.7 关闭 Socket

当通信结束后,可以使用 close() 函数关闭 Socket:

#include <unistd.h>

int close(int sockfd);

TCP Socket 编程

4.1 TCP 服务器

以下是一个简单的 TCP 服务器示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.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};
    char *response = "Hello from server";

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

    // 绑定 Socket
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("Bind failed");
        close(server_fd);
        exit(EXIT_FLURE);
    }

    // 监听连接
    if (listen(server_fd, 3) < 0) {
        perror("Listen failed");
        close(server_fd);
        exit(EXIT_FLURE);
    }

    // 接受连接
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
        perror("Accept failed");
        close(server_fd);
        exit(EXIT_FLURE);
    }

    // 接收数据
    read(new_socket, buffer, BUFFER_SIZE);
    printf("Received: %s\n", buffer);

    // 发送数据
    send(new_socket, response, strlen(response), 0);
    printf("Response sent\n");

    // 关闭 Socket
    close(new_socket);
    close(server_fd);
    return 0;
}

4.2 TCP 客户端

以下是一个简单的 TCP 客户端示例:

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

#define PORT 8080
#define BUFFER_SIZE 1024

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

    // 创建 Socket
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("Socket creation error");
        exit(EXIT_FLURE);
    }

    // 设置服务器地址
    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/ Address not supported");
        close(sock);
        exit(EXIT_FLURE);
    }

    // 连接服务器
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("Connection Failed");
        close(sock);
        exit(EXIT_FLURE);
    }

    // 发送数据
    send(sock, message, strlen(message), 0);
    printf("Message sent\n");

    // 接收数据
    read(sock, buffer, BUFFER_SIZE);
    printf("Received: %s\n", buffer);

    // 关闭 Socket
    close(sock);
    return 0;
}

UDP Socket 编程

5.1 UDP 服务器

以下是一个简单的 UDP 服务器示例:

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

#define PORT 8080
#define BUFFER_SIZE 1024

int main() {
    int sockfd;
    struct sockaddr_in servaddr, cliaddr;
    char buffer[BUFFER_SIZE];
    char *response = "Hello from server";

    // 创建 Socket
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("Socket creation failed");
        exit(EXIT_FLURE);
    }

    // 绑定 Socket
    memset(&servaddr, 0, sizeof(servaddr));
    memset(&cliaddr, 0, sizeof(cliaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = INADDR_ANY;
    servaddr.sin_port = htons(PORT);
    if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
        perror("Bind failed");
        close(sockfd);
        exit(EXIT_FLURE);
    }

    // 接收数据
    int len, n;
    len = sizeof(cliaddr);
    n = recvfrom(sockfd, (char *)buffer, BUFFER_SIZE, MSG_WTALL, (struct sockaddr *)&cliaddr, &len);
    buffer[n] = '\0';
    printf("Received: %s\n", buffer);

    // 发送数据
    sendto(sockfd, (const char *)response, strlen(response), MSG_CONFIRM, (const struct sockaddr *)&cliaddr, len);
    printf("Response sent\n");

    // 关闭 Socket
    close(sockfd);
    return 0;
}

5.2 UDP 客户端

以下是一个简单的 UDP 客户端示例:

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

#define PORT 8080
#define BUFFER_SIZE 1024

int main() {
    int sockfd;
    struct sockaddr_in servaddr;
    char *message = "Hello from client";
    char buffer[BUFFER_SIZE];

    // 创建 Socket
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("Socket creation failed");
        exit(EXIT_FLURE);
    }

    // 设置服务器地址
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(PORT);
    if (inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr) <= 0) {
        perror("Invalid address/ Address not supported");
        close(sockfd);
        exit(EXIT_FLURE);
    }

    // 发送数据
    sendto(sockfd, (const char *)message, strlen(message), MSG_CONFIRM, (const struct sockaddr *)&servaddr, sizeof(servaddr));
    printf("Message sent\n");

    // 接收数据
    int len, n;
    len = sizeof(servaddr);
    n = recvfrom(sockfd, (char *)buffer, BUFFER_SIZE, MSG_WTALL, (struct sockaddr *)&servaddr, &len);
    buffer[n] = '\0';
    printf("Received: %s\n", buffer);

    // 关闭 Socket
    close(sockfd);
    return 0;
}

高级 Socket 编程

6.1 多路复用

多路复用允许一个进程同时监控多个 Socket,常用的多路复用技术包括 select()poll()epoll()

6.1.1 select()

select() 函数允许程序监控多个文件描述符,直到其中一个或多个文件描述符变为可读、可写或发生异常。

#include <sys/select.h>

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

6.1.2 poll()

poll() 函数与 select() 类似,但提供了更灵活的接口。

#include <poll.h>

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

6.1.3 epoll()

epoll() 是 Linux 特有的多路复用机制,适用于大规模并发连接。

#include <sys/epoll.h>

int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

6.2 非阻塞 Socket

非阻塞 Socket 允许程序在等待 I/O 操作完成时继续执行其他任务。可以通过 fcntl() 函数将 Socket 设置为非阻塞模式。

#include <fcntl.h>

int flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

6.3 信号驱动 I/O

信号驱动 I/O 允许程序在数据到达时接收信号,从而避免轮询。

#include <signal.h>
#include <fcntl.h>

void sigio_handler(int signo) {
    // 处理数据到达
}

int main() {
    signal(SIGIO, sigio_handler);
    fcntl(sockfd, F_SETOWN, getpid());
    fcntl(sockfd, F_SETFL, O_ASYNC | O_NONBLOCK);
    // 其他代码
}

6.4 异步 I/O

异步 I/O 允许程序在 I/O 操作完成时接收通知,而不需要等待操作完成。

#include <aio.h>

struct aiocb aio;
aio.aio_fildes = sockfd;
aio.aio_buf = buffer;
aio.aio_nbytes = BUFFER_SIZE;
aio.aio_offset = 0;
aio.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
aio.aio_sigevent.sigev_signo = SIGIO;
aio_read(&aio);

Socket 编程中的常见问题

7.1 地址重用

在服务器重启时,可能会遇到地址已被占用的问题。可以通过设置 SO_REUSEADDR 选项来重用地址。

int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

7.2 超时设置

可以通过设置 SO_RCVTIMEOSO_SNDTIMEO 选项来设置接收和发送的超时时间。

”`c struct timeval timeout; timeout.tv_sec = 5; timeout.tv_usec = 0; setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); setsockopt(sockfd, SOL_SOCKET, SO

推荐阅读:
  1. linux 安装 python3
  2. Linux如何安装mysql 8.0

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

linux socket

上一篇:linux swap是怎么触发的

下一篇:linux中buffer和cache的区别有哪些

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》