c - 通过 c 中的套接字从结构中传递字符
问题描述
我正在尝试在我的服务器和客户端之间发送/接收消息。我目前在我的服务器中有一个保存 char 值的结构。我正在尝试将此值传递给我的客户。请参阅以下内容:
tileInfo->tiles[user_cords_x][user_cords_y].identifier = '+'; // Char i want to pass
write_client_msg(cli_sockfd, &tileInfo->tiles[user_cords_x][user_cords_y].identifier);
/* Writes a message to a client socket. */
void write_client_msg(int cli_sockfd, char * msg)
{
int n = write(cli_sockfd, msg, strlen(msg));
if (n < 0)
error("ERROR writing msg to client socket");
}
在我的客户端,我收到以下内容:
char *msg;
char identity = read(sockfd, msg, 1);
printf("This is the value: %d \n", identity);
目前我得到的输出是This is the value: 1
. 我是套接字新手,不完全理解传递的字符。有人可以解释一下并告诉我如何将“+”传递给我的客户端吗?
解决方案
您的代码犯了几个错误。
在服务器端,在此代码中:
write_client_msg(cli_sockfd, &tileInfo->tiles[user_cords_x][user_cords_y].identifier);
很明显那identifier
是一个单一的char
,否则代码将无法编译。在这种情况下,使用strlen()
inside ofwrite_client_msg()
是错误的,因为msg
在传递指向单个 的指针时不会有空终止符char
。您最终会将垃圾传输给另一方,如果不是因为访问无效内存而完全崩溃。
然后,在客户端,您将一个未初始化的msg
指针传递给read()
. 而且,您正在显示read()
的返回值,即实际接收到的字节数。这就是您的显示器显示的原因1
,因为您要求接收 1 个字节。
要正确发送和接收identifier
,您需要更多类似的东西:
void write_client_msg(int sockfd, char *msg, size_t msg_len)
{
int n = write(sockfd, msg, msg_len);
if (n < 0)
error("ERROR writing msg to client socket");
}
...
write_client_msg(cli_sockfd, &tileInfo->tiles[user_cords_x][user_cords_y].identifier, 1);
char identity;
int n = read(sockfd, &identity, 1);
if (n < 0)
error("ERROR reading identity from client socket");
else if (n == 0)
error("DISCONNECTED while reading identity from client socket");
else
printf("This is the value: %c \n", identity);
话虽如此,更好的解决方案是在write_client_msg()
发送. 特别是因为不知道它正在发送什么样的数据。然后客户端可以读取以知道要为 读取多少字节,然后根据需要处理 。msg_len
msg
write_client_msg()
msg_len
msg
msg
此外,write()
并且read()
可以返回比请求更少的字节,因此您需要在循环中调用它们以确保您实际发送/接收所有内容。
例如:
int write_all(int sockfd, void *data, size_t data_len)
{
char *d = (char*) data;
while (data_len > 0)
{
int n = write(sockfd, d, data_len);
if (n < 0)
return n;
d += n;
data_len -= n;
}
return 1;
}
void write_client_msg(int sockfd, char *msg, size_t msg_len)
{
uint32_t len = htonl(msg_len);
int n = write_all(sockfd, &len, sizeof(len));
if (n == 1)
n = write_all(sockfd, msg, msg_len);
if (n < 0)
error("ERROR writing msg to client socket");
}
...
write_client_msg(cli_sockfd, &tileInfo->tiles[user_cords_x][user_cords_y].identifier, 1);
int read_all(int sockfd, void *data, size_t data_len)
{
char *d = (char*) data;
while (data_len > 0)
{
int n = read(sockfd, d, data_len);
if (n <= 0)
return n;
d += n;
data_len -= n;
}
return 1;
}
char *read_server_msg(int sockfd)
{
uint32_t len;
int n = read_all(sockfd, &len, sizeof(len));
if (n <= 0)
return NULL;
len = ntohl(len);
char *msg = malloc(len+1);
if (!msg)
return NULL;
n = read_all(sockfd, msg, len);
if (n <= 0) {
free(msg);
return NULL;
}
msg[len] = '\0';
return msg;
}
...
char *msg = read_server_msg(sockfd);
if (!msg)
error("ERROR reading msg from client socket");
else {
printf("This is the value: %s \n", msg);
free(msg);
}
推荐阅读
- angular - Angular:行为主体的值对象不可扩展
- nginx - 如何使用 uwsgi-socket 与 nginx 进行负载平衡
- node.js - Angular - TypeError 无法将 _id 设置为空值
- android - Android Studio AlarmManager 在特定时间没有运行
- sql - COUNT(*) 函数返回多个值
- java - 如何使用@RequestParam 捕获多个 url 参数?
- javascript - 如何在制表器中显示嵌套列表数据
- rest - 如何同时使用 SOAP WCF 服务和 REST API
- maven - 如果子模块的 nexus 上传失败,请跳过并尝试其他模块
- events - Apache Royale Jewel TabBar / SectionContent onShow 或 valueCommit 事件,如 sdk 0.9.8?