Linux中的read/write和recv/send的区别,并使用recv/send实现简单的聊天功能

r e a d / w r i t e read/write read/write的用法

在 Linux 中,read() 和 write() 是用于在文件描述符上进行数据读写的函数。它们的用法如下:

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);

ssize_t write(int fd, const void *buf, size_t count);

其中, f d fd fd 是一个已经打开的文件描述符;
b u f buf buf 是一个指向读或写数据的缓冲区指针;
c o u n t count count 是缓冲区的长度。

r e a d ( ) read() read() 函数用于从文件描述符中读取数据,它会阻塞程序直到读取到数据或发生错误。它返回读取到的字节数,如果返回值为 0 0 0,则表示已经到达文件末尾。如果返回值为 − 1 -1 1,则表示出现了错误,可以通过 e r r n o errno errno 变量来获取错误码。

w r i t e ( ) write() write() 函数用于向文件描述符中写入数据,它会阻塞程序直到所有数据都被写入完毕或发生错误。它返回写入的字节数,如果返回值小于指定的长度,则表示出现了错误。可以通过 e r r n o errno errno 变量来获取错误码。

需要注意的是, r e a d ( ) read() read() w r i t e ( ) write() write() 是基于字节流的,它们不会保留消息的边界信息。如果需要保留消息的边界信息,可以使用 r e a d ( ) read() read() w r i t e ( ) write() write() 函数。

r e c v / s e n d recv/send recv/send的用法

L i n u x Linux Linux 中, r e c v ( ) 和 s e n d ( ) recv() 和 send() recv()send() 是用于在网络套接字上进行数据收发的函数。它们的用法如下:

#include <sys/socket.h>

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

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

其中, s o c k f d sockfd sockfd 是一个已经创建好的、打开的套接字文件描述符;
b u f buf buf 是一个指向接收或发送数据的缓冲区指针;
l e n len len 是缓冲区的长度;
f l a g s flags flags 是一组标志参数,它们控制着函数的行为。

r e c v ( ) recv() recv() 函数用于从套接字中接收数据,它会阻塞程序直到接收到数据或发生错误。它返回接收到的字节数,如果返回值为 0 0 0,则表示连接已经关闭。如果返回值为 − 1 -1 1,则表示出现了错误,可以通过 e r r n o errno errno 变量来获取错误码。 r e c v ( ) recv() recv() 函数的常用标志参数有:

  • MSG_WAITALL:阻塞等待直到接收到指定长度的数据。
  • MSG_PEEK:接收数据但不从接收缓冲区中删除数据。
  • MSG_OOB:接收带外数据。

s e n d ( ) send() send() 函数用于向套接字中发送数据,它会阻塞程序直到所有数据都被发送完毕或发生错误。它返回发送的字节数,如果返回值小于指定的长度,则表示出现了错误。可以通过 e r r n o errno errno 变量来获取错误码。 s e n d ( ) send() send() 函数的常用标志参数有:

  • MSG_DONTWAIT:非阻塞发送数据。
  • MSG_MORE:告诉内核还有更多数据需要发送。
  • MSG_NOSIGNAL:在发送数据时忽略 SIGPIPE 信号。

L i n u x Linux Linux中的 r e a d / w r i t e read/write read/write r e c v / s e n d recv/send recv/send的区别

L i n u x Linux Linux中, r e a d / w r i t e read/write read/write r e c v / s e n d recv/send recv/send是用于从 文件描述符 文件描述符 文件描述符 套接字 套接字 套接字进行数据读写的系统调用。它们之间的主要区别如下:

  1. 参数不同
    r e a d / w r i t e read/write read/write的参数是 文件描述符、缓冲区和读 / 写字节数 文件描述符、缓冲区和读/写字节数 文件描述符、缓冲区和读/写字节数
    r e c v / s e n d recv/send recv/send的参数是 套接字、缓冲区和读 / 写字节数 套接字、缓冲区和读/写字节数 套接字、缓冲区和读/写字节数

  2. 返回值不同
    r e a d / w r i t e read/write read/write的返回值为已读/写字节数,如果遇到错误则返回-1。
    r e c v / s e n d recv/send recv/send的返回值为已接收/发送字节数,如果遇到错误则返回-1。

  3. 应用场景不同
    r e a d / w r i t e read/write read/write通常用于 读写普通的文件、管道等 读写普通的文件、管道等 读写普通的文件、管道等
    r e c v / s e n d recv/send recv/send则用于 网络编程中的套接字通信 网络编程中的套接字通信 网络编程中的套接字通信

  4. 处理方式不同
    r e a d / w r i t e read/write read/write在读写时使用文件偏移量来确定从哪里读取或写入数据,并根据需要更新该偏移量。
    r e c v / s e n d recv/send recv/send则没有类似的偏移量概念,它们一次性读取或发送指定数量的数据。

总体而言, r e a d / w r i t e read/write read/write适合用于本地文件和管道等,而 r e c v / s e n d recv/send recv/send适合用于网络通信中的套接字。

下面是一个使用read/write进行文件读写操作的例子:

该程序打开一个名为 t e s t . t x t test.txt test.txt的文件,并使用 r e a d read read将其内容读取到缓冲区中,然后使用 w r i t e write write将内容写入标准输出。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>

int main() {
    int fd = open("test.txt", O_RDWR);
    if (fd == -1) {
        printf("Failed to open file\n");
        exit(1);
    }
    
    char buffer[1024];
    int num_read = read(fd, buffer, sizeof(buffer));
    if (num_read == -1) {
        printf("Failed to read file\n");
        exit(1);
    }
    
    int num_written = write(STDOUT_FILENO, buffer, num_read);
    if (num_written == -1) {
        printf("Failed to write file\n");
        exit(1);
    }

    close(fd);
    return 0;
}

下面是一个使用recv/send进行网络通信的例子:

下面是一个使用recv/send进行网络通信的服务器与客户端互发消息的例子:

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

#define PORT 8081

int main()
{
    int server_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (server_sock == -1)
    {
        printf("Failed to create socket\n");
        exit(1);
    }

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
    {
        printf("Failed to bind\n");
        exit(1);
    }

    if (listen(server_sock, 5) == -1)
    {
        printf("Failed to listen\n");
        exit(1);
    }

    printf("Server is listening on port %d...\n", PORT);

    struct sockaddr_in client_addr;
    socklen_t client_addr_len = sizeof(client_addr);
    int client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_addr_len);
    if (client_sock == -1)
    {
        printf("Failed to accept connection\n");
        exit(1);
    }

    char buffer[1024];
    while (1)
    {

        memset(buffer, 0, sizeof buffer);                                // 收之前先把缓存区清空
        int num_received = recv(client_sock, buffer, sizeof(buffer), 0); /收///
        if (num_received == -1)
        {
            printf("Failed to receive message\n");
            exit(1);
        }
        else if (num_received == 0)
        {
            break; // Client closed connection
        }

        printf("Received message: %s", buffer);

        const char *message = "Hello, client!\n";
        int num_sent = send(client_sock, message, strlen(message), 0); ///发
        if (num_sent == -1)
        {
            printf("Failed to send message\n");
            exit(1);
        }
    }

    close(client_sock);
    close(server_sock);
    return 0;
}

该程序创建了一个服务器套接字,绑定到指定端口,并使用listen开始监听。当客户端连接时,使用accept接受连接并进行通信。在接受到客户端发送的消息后,服务器会将其打印出来,并向客户端发送一条回复。

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

#define PORT 8081

int main()
{
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == -1)
    {
        printf("Failed to create socket\n");
        exit(1);
    }

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

    if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
    {
        printf("Failed to connect\n");
        exit(1);
    }

    char buffer[1024];
    while (1)
    {
        printf("Enter message: ");
        fgets(buffer, sizeof(buffer), stdin);

        int num_sent = send(sock, buffer, strlen(buffer), 0); /发/
        if (num_sent == -1)
        {
            printf("Failed to send message\n");
            exit(1);
        }
        else if (num_sent == 0)
        {
            break; // Server closed connection
        }

        memset(buffer, 0, sizeof buffer);                         // 收之前先把缓存区清空
        int num_received = recv(sock, buffer, sizeof(buffer), 0); /收//
        if (num_received == -1)
        {
            printf("Failed to receive message\n");
            exit(1);
        }
        else if (num_received == 0)
        {
            break; // Server closed connection
        }

        printf("Received message: %s", buffer);
    }

    close(sock);
    return 0;
}

该程序创建了一个客户端套接字,连接到服务器。在输入一条消息后,使用send向服务器发送该消息,并收到服务器的回复。当检测到服务器关闭连接时,程序退出。

这两个程序可以相互通信,实现简单的聊天功能。
在这里插入图片描述

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

踏过山河,踏过海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值