简体   繁体   English

unix 套接字数据报:服务器接收到无效字符

[英]unix socket datagram: server receive invalid characters

I'm trying to create a Unix socket datagram example.我正在尝试创建一个 Unix 套接字数据报示例。 The client can send and receive message smoothly.客户端可以顺利发送和接收消息。 The server is able to do that just in case the buffer length is smaller than SOCKET_BUFFER_SIZE , otherwise the server's output shows some invalid characters at received buffer.服务器可以这样做,以防缓冲区长度小于SOCKET_BUFFER_SIZE ,否则服务器的 output 在接收的缓冲区中显示一些无效字符。

Client's code客户代码

#include "ud_hdr.h"

#define IN_BUF_SIZE     200

int main(int argc, char **argv)
{
    struct sockaddr_un  svr_addr, cli_addr;
    int                 sfd, i;
    ssize_t             num_rw;
    socklen_t           svr_addr_len;
    char                sock_buf[SOCK_BUF_SIZE];
    char                in_buf[IN_BUF_SIZE];

    // Create sockets:
    sfd = socket(AF_UNIX, SOCK_DGRAM, 0);
    if (sfd == -1) {
        printf("Error line|%d|: %s", __LINE__, strerror(errno));
        exit(EXIT_FAILURE);
    }

    // ! In Unix domain, the client needs to assign an address to its socket
    // ! if it wants to RECEIVE datagrams sent by server.
    memset(&cli_addr, 0, sizeof(struct sockaddr_un));
    cli_addr.sun_family = AF_UNIX;
    snprintf(cli_addr.sun_path, sizeof(cli_addr.sun_path), \
            "/tmp/dxduc/ud_cli.%ld", (long)getpid());
    if (bind(sfd, (struct sockaddr *) &cli_addr, sizeof(struct sockaddr_un)) == -1) {
        printf("Error line|%d|: %s\n", __LINE__, strerror(errno));
        exit(EXIT_FAILURE);
    }

    // Construct server's address:
    memset(&svr_addr, 0, sizeof(struct sockaddr_un));
    svr_addr.sun_family = AF_UNIX;
    strncpy(svr_addr.sun_path, SOCKET_SV_PATH, sizeof(svr_addr.sun_path) - 1);

    printf("Client is ready to run\n");
    while (1) {
        printf("Enter new msg: ");
        fflush(stdout); // * clear the output buffer and move the buffered data to output (a.k.a console in this case)
        memset(in_buf, 0, sizeof(in_buf));
        memset(sock_buf, 0, sizeof(sock_buf));
        num_rw = read(STDIN_FILENO, in_buf, IN_BUF_SIZE);

        // Remove '\n' and '\r' in input:
        for (i = 0; i < IN_BUF_SIZE; i++) {
            // if ((in_buf[i] == '\r') || (in_buf[i] == '\n')) {
            if (in_buf[i] == '\n') {
                in_buf[i] = 0x0;
            }
        }

        printf("Msg to server: |%s|, len = %ld, num_rw = %ld\n", in_buf, strlen(in_buf), num_rw);
        svr_addr_len = sizeof(struct sockaddr_un);
        if (num_rw > 0) {
            // Send msg to server:
            if (sendto(sfd, in_buf, strlen(in_buf), 0, (struct sockaddr *) &svr_addr, svr_addr_len) != strlen(in_buf)) {
                printf("Error line|%d|: %s\n", __LINE__, strerror(errno));
                exit(EXIT_FAILURE);
            }
        } else if (num_rw == 0) {
            printf("Nothing to send to server\n");
            continue;
        } else if (num_rw == -1) {
            printf("Error line|%d|: %s\n", __LINE__, strerror(errno));
            exit(EXIT_FAILURE);
        }

        // Read response from server
        num_rw = recvfrom(sfd, sock_buf, SOCK_BUF_SIZE, 0, (struct sockaddr *) &svr_addr, &svr_addr_len);
        if (num_rw == -1) {
            printf("Error line|%d|, %s", __LINE__, strerror(errno));
            exit(EXIT_FAILURE);
        } else {
            printf("Receive from server: |%s|, len=%ld, num_rw=%ld\n", sock_buf, strlen(sock_buf), num_rw);
        }
    }
}

Server's code服务器的代码

#include "ud_hdr.h"

int main(int argc, char **argv)
{
    struct sockaddr_un  svr_addr, cli_addr;
    int                 sfd, i;
    ssize_t             num_rw;
    socklen_t           cli_addr_len;
    char                buf[SOCK_BUF_SIZE];

    // Create socket:
    sfd = socket(AF_UNIX, SOCK_DGRAM, 0);
    if (sfd == -1) {
        printf("Error line|%d|: %s\n", __LINE__, strerror(errno));
        exit(EXIT_FAILURE);
    }

    // Verify socket's name path:
    if (strlen(SOCKET_SV_PATH) > (sizeof(svr_addr.sun_path) - 1)) {
        printf("Error line|%d|: invalid socket name", __LINE__);
        exit(EXIT_FAILURE);
    }

    // Remove any existing file having the same namepath with server's:
    if ((remove(SOCKET_SV_PATH) == -1) && (errno != ENOENT)) {
        printf("Error line|%d|: %s\n", __LINE__, strerror(errno));
        exit(EXIT_FAILURE);
    }

    // Bind the socket to desired addr:
    memset(&svr_addr, 0, sizeof(struct sockaddr_un));
    svr_addr.sun_family = AF_UNIX;
    strncpy(svr_addr.sun_path, SOCKET_SV_PATH, sizeof(svr_addr.sun_path) - 1);

    if (bind(sfd, (struct sockaddr *)&svr_addr, sizeof(struct sockaddr_un)) == -1) {
        printf("Error line|%d|: %s\n", __LINE__, strerror(errno));
        exit(EXIT_FAILURE);
    }

    while (1) {
        // Receive data from client:
        memset(buf, 0, sizeof(buf));
        cli_addr_len = sizeof (struct sockaddr_un);
        num_rw = recvfrom(sfd, buf, SOCK_BUF_SIZE, 0, (struct sockaddr *) &cli_addr, &cli_addr_len);

        if (num_rw == -1) {
            printf("Error line|%d|: %s\n", __LINE__, strerror(errno));
            exit(EXIT_FAILURE);
        }

        printf("Server received %ld bytes from %s, ret_buf=|%s|, len=%ld\n", (long)num_rw, cli_addr.sun_path, buf, strlen(buf));

        // Uppercase received characters:
        for (i = 0; i < num_rw; i++) {
            buf[i] = toupper((unsigned char)buf[i]);
        }

        // Send back uppercase-ed characters to client:
        printf("Send back to client: |%s|, len=%ld\n", buf, strlen(buf));
        if (sendto(sfd, buf, strlen(buf), 0, (struct sockaddr *) &cli_addr, cli_addr_len) != strlen(buf)) {
            printf("Error line|%d|: %s\n", __LINE__, strerror(errno));
            exit(EXIT_FAILURE);
        }
    }
}

Header file Header文件

#ifndef _UD_HDR_H_
#define _UD_HDR_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

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

#include <errno.h>
#include <unistd.h>
#include <ctype.h>

// * The Makefile should have created /tmp/dxduc before run this program
#define SOCKET_SV_PATH      "/tmp/dxduc/ud_basic"
#define SOCK_BUF_SIZE            10

#endif // _UD_HDR_H_

This is what I got这就是我得到的

# Client
Client is ready to run
Enter new msg: stack  
Msg to server: |stack|, len = 5, num_rw = 6
Receive from server: |STACK|, len=5, num_rw=5
Enter new msg: stackoverflow
Msg to server: |stackoverflow|, len = 13, num_rw = 14
Receive from server: |STACKOVERF|, len=10, num_rw=10

#Server
Server received 5 bytes from /tmp/dxduc/ud_cli.2385, ret_buf=|stack|, len=5
Send back to client: |STACK|, len=5
Server received 10 bytes from /tmp/dxduc/ud_cli.2385, ret_buf=|stackoverf�  |, len=14
Send back to client: |STACKOVERF�   |, len=14

It's weird that the client received the expected message, though the server did not format the message correctly before sending it.很奇怪,客户端收到了预期的消息,尽管服务器在发送之前没有正确格式化消息。

This is my expected output这是我预期的 output

# Client
Client is ready to run
Enter new msg: stack  
Msg to server: |stack|, len = 5, num_rw = 6
Receive from server: |STACK|, len=5, num_rw=5
Enter new msg: stackoverflow
Msg to server: |stackoverflow|, len = 13, num_rw = 14
Receive from server: |STACKOVERF|, len=10, num_rw=10

#Server
Server received 5 bytes from /tmp/dxduc/ud_cli.2385, ret_buf=|stack|, len=5
Send back to client: |STACK|, len=5
Server received 10 bytes from /tmp/dxduc/ud_cli.2385, ret_buf=|stackoverf|, len=10
Send back to client: |STACKOVERF|, len=14

How should I solve it?我该如何解决?

Your SOCK_BUF_SIZE is 10 and you receive 10 bytes (in your client).您的SOCK_BUF_SIZE为 10,您收到 10 个字节(在您的客户端中)。 It overwrites your 0 byte.它会覆盖您的 0 字节。 You should use你应该使用

char sock_buf[SOCK_BUF_SIZE+1];

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM