Linux 下的 Socket 和进程使用

Linux 下的 Socket 和进程使用

在 Linux 环境中,通过搭建服务器端和客户端服务来实现 Socket 通信,并利用多进程来有效地管理客户端。

Socket 通讯流程

下面是 socket 服务端和客户端通讯流程:

使用 Socket 我们需要了解几个常用的函数:

服务端:

socket

NAME
socket - create an endpoint for communication

SYNOPSIS
#include <sys/types.h> /_ See NOTES _/
#include <sys/socket.h>

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

socket 函数用来创建一个通信端点, domain 为指定通信域, 常用通信协议族有 AF_INET( IPv4),AF_INET6(IPv6);type 为 socket,常用的有 SOCK_STREAM(TCP),SOCK_DGRAM(UDP);protocol 指定通信协议,可以使用默认 0。

bind

NAME
bind - bind a name to a socket

SYNOPSIS
#include <sys/types.h> /_ See NOTES _/
#include <sys/socket.h>

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

使用 bind 绑定 socket 文件描述符。

listen

NAME
listen - listen for connections on a socket

SYNOPSIS
#include <sys/types.h> /_ See NOTES _/
#include <sys/socket.h>

   int listen(int sockfd, int backlog);

使用 listen 监听 socket 连接。

accept

NAME
accept, accept4 - accept a connection on a socket

SYNOPSIS
#include <sys/types.h> /_ See NOTES _/
#include <sys/socket.h>

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

使用 accept 接受 socket 连接。

recv

NAME
recv, recvfrom, recvmsg - receive a message from a socket

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

使用 recv 函数接收 socket 消息。

send

NAME
send, sendto, sendmsg - send a message on a socket

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

使用 send 函数发送 socket 消息。

connect

NAME
connect - initiate a connection on a socket

SYNOPSIS
#include <sys/types.h> /_ See NOTES _/
#include <sys/socket.h>

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

客户端可以使用 connect 连接到 socket 服务端。

close

NAME
close - close a file descriptor

SYNOPSIS
#include <unistd.h>

   int close(int fd);

关闭 socket。

Socket 代码实现

server.c

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

#define MAX_PADDING 10
#define MAX_LINE 256

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        fprintf(stderr, "Usage: %s <server_address> <port>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    int s_fd, c_fd;

    char buf[MAX_LINE];

    struct sockaddr_in server_addr, client_addr;

    int len, bytes_received;

    s_fd = socket(AF_INET, SOCK_STREAM, 0);

    if (s_fd == -1)
    {
        perror("Socket error");
        exit(1);
    }

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(argv[1]);
    server_addr.sin_port = htons(atoi(argv[2]));

    printf("server address: %s:%s\n", argv[1], argv[2]);

    int status = bind(s_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (status == -1)
    {
        perror("Bind  error");
        close(s_fd);
        exit(1);
    }

    if (listen(s_fd, MAX_PADDING) == -1)
    {
        perror("Listeb error");
        close(s_fd);
        exit(1);
    }

    printf("服务器等待连接,端口号:%s...\n", argv[2]);

    // 接收来自客户端的数据
    while (1)
    {
        len = sizeof(client_addr);

        c_fd = accept(s_fd, (struct sockaddr *)&client_addr, &len);

        if (c_fd == -1)
        {
            perror("Accept error");
            close(s_fd);
            exit(1);
        }

        printf("连接成功,客户端地址:%s,端口号:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

        while (1)
        {
            // 接受来自客户端的数据
            bytes_received = recv(c_fd, buf, MAX_LINE, 0);
            if (bytes_received > 0)
            {
                buf[bytes_received] = '\0';
                printf("接收到的消息:%s", buf);

                // 回显数据给客户端
                if (send(c_fd, buf, bytes_received, 0) == -1)
                {
                    perror("Send error");
                    close(c_fd);
                    close(s_fd);
                    exit(1);
                }
            }
            else if (bytes_received == -1)
            {
                perror("Receive error");
                exit(EXIT_FAILURE);
            }
        }
    }

    close(s_fd);

    return 0;
}

client.c

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

#define MAX_LINE 256

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        fprintf(stderr, "Usage: %s <server_address> <port>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    int c_fd;
    char buf[MAX_LINE];
    struct sockaddr_in client_addr;
    int len, bytes_sent;

    if ((c_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("Socket error");
        exit(1);
    }

    // 初始化服务器地址结构
    memset(&client_addr, 0, sizeof(client_addr));
    client_addr.sin_family = AF_INET;
    client_addr.sin_addr.s_addr = inet_addr(argv[1]);
    client_addr.sin_port = htons(atoi(argv[2]));

    int status = connect(c_fd, (struct sockaddr *)&client_addr, sizeof(client_addr));
    if (status == -1)
    {
        perror("Connect error");
        close(c_fd);
        exit(1);
    }

    printf("已连接到服务器,端口号:%s\n", argv[2]);

    while (1)
    {
        // 发送数据到服务器
        printf("请输入要发送给服务器的消息(输入 quit 退出):");
        fgets(buf, MAX_LINE, stdin);

        if (strcmp(buf, "quit\n") == 0)
            break;

        bytes_sent = send(c_fd, buf, sizeof(buf), 0);
        if (bytes_sent == -1)
        {
            perror("Send error");
            close(c_fd);
            exit(1);
        }
        printf("发送 %d 字节到服务器\n", bytes_sent);

        // 接收来自服务器的回复
        len = recv(c_fd, buf, MAX_LINE, 0);
        if (len == -1)
        {
            perror("Receive error");
            close(c_fd);
            exit(EXIT_FAILURE);
        }

        buf[len] = '\0';
        printf("接收到服务器的回复:%s", buf);
    }

    // 关闭套接字
    close(c_fd);

    return 0;
}


END

  • 13
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值