unix 套接字数据报:服务器接收到无效字符
Posted
技术标签:
【中文标题】unix 套接字数据报:服务器接收到无效字符【英文标题】:unix socket datagram: server receive invalid characters 【发布时间】:2021-02-04 09:47:28 【问题描述】:我正在尝试创建一个 Unix 套接字数据报示例。客户端可以顺利发送和接收消息。服务器可以这样做,以防缓冲区长度小于SOCKET_BUFFER_SIZE
,否则服务器的输出会在接收的缓冲区中显示一些无效字符。
客户代码
#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);
服务器的代码
#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);
头文件
#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_
这就是我得到的
# 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: ***
Msg to server: |***|, 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
奇怪的是客户端收到了预期的消息,尽管服务器在发送之前没有正确格式化消息。
这是我的预期输出
# 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: ***
Msg to server: |***|, 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
我该如何解决?
【问题讨论】:
你的缓冲区可能不是零终止的 @dvhh 你说的是哪个缓冲区?客户端准备发送到服务器的缓冲区? @dvhh 没有“可能”。sendto(sfd, in_buf, strlen(in_buf), 0, (struct sockaddr *) &svr_addr, svr_addr_len)
不会发送正确的 C 字符串,因为它将 not 以零结尾。
@AndrewHenle 我知道如何解决这个问题,谢谢
【参考方案1】:
您的 SOCK_BUF_SIZE
为 10,您收到 10 个字节(在您的客户端中)。它会覆盖您的 0 字节。
你应该使用
char sock_buf[SOCK_BUF_SIZE+1];
【讨论】:
以上是关于unix 套接字数据报:服务器接收到无效字符的主要内容,如果未能解决你的问题,请参考以下文章
Unix Domain Socket:在一个服务器进程和多个客户端进程之间使用数据报通信