【发布时间】:2021-04-12 11:32:21
【问题描述】:
我创建了两个程序,一个客户端和一个服务器。它们通过发送固定大小为 115 字节的 char 数组的套接字进行通信。
我要传输的数据存放在以下struct:
typedef struct {
char origin[14];
char type;
char data[100];
} socket_data;
但为了发送序列化的数据,我想以单个字符串发送该信息,该字符串连接struct 中的所有字段,因此我发送了一个 115 字节的字符串。如果这些字段中的任何一个未达到其最大大小,我将使用 \0 手动填充额外的数组位置。
我创建了两个在客户端和服务器中实现的函数,它们通过套接字发送数据或从套接字接收数据。
两个函数如下:
void socket_send(int socket, char *origin, char type, char *data) {
char info[115]; //data to be sent
socket_data aux;
strcpy(aux.origin, origin);
aux.type = type;
strcpy(aux.data, data);
//Filling up the remaining positions of origin and data variables
for (int i = (int) strlen(aux.origin); i<14; i++) aux.origin[i] = '\0';
for (int i = (int) strlen(aux.data); i<100; i++) aux.data[i] = '\0';
//Building up the 115 byte string I want to send via socket
for (int i=0; i<14; i++) info[i] = aux.origin[i];
info[14] = type;
for (int i=0; i<100; i++) info[i+15] = aux.data[i];
ssize_t total_bytes = 115;
ssize_t bytes_written = 0;
//Here I send all the bytes through the socket
do {
bytes_written = write(socket, info + (115 - total_bytes), total_bytes);
total_bytes -= bytes_written;
} while (total_bytes > 0);
}
socket_data socket_rcv(int socket) {
socket_data info;
char sequence[115];
ssize_t total_bytes = 115;
ssize_t bytes_read = 0;
//Here I receive all the bytes from the socket (till I fill up the 115 byte string called sequence)
do {
bytes_read = read(socket, sequence + (115 - total_bytes), total_bytes);
total_bytes -= bytes_read;
} while (total_bytes > 0);
//Then I return a stuct
for (int i=0; i<14; i++) info.origin[i] = sequence[i];
info.type = sequence[14];
for (int i=0; i<100; i++) info.data[i] = sequence[i+15];
return info;
}
如您所见,我循环 read() 和 write() 以确保发送所有字节,因为我知道有时这些函数读取或写入的字节数少于要求的字节数。
问题是,在测试程序的功能时,我发现在读取的字节数较少(它循环)的情况下,程序会阻塞(可能等待来自服务器端的另一个 write())而不是读取套接字缓冲区中的剩余字节(因为发送了所有 115 个字节而只接收了 111 个字节,所以套接字缓冲区中应该还有 4 个字节)。有时,程序不会阻塞等待可能的write(),而是在它不应该终止时终止......
我在这里找不到问题,希望能得到一些帮助
编辑
我创建了这个函数来设置套接字...
服务器:
int socketConfig (connection_info cinfo) {
int socketfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socketfd < 0) {
write(1, "Socket error\n", strlen("Socket error\n"));
return -1;
}
struct sockaddr_in s_addr;
memset (&s_addr, 0, sizeof (s_addr));
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(cinfo.port);
s_addr.sin_addr.s_addr = INADDR_ANY;
if (bind (socketfd, (void *) &s_addr, sizeof (s_addr)) < 0) {
write(1, "Bind error\n", strlen("Bind error\n"));
return -1;
}
listen(socketfd, 3);
return socketfd;
}
int receiveClient(int serverfd) {
struct sockaddr_in client;
socklen_t len = sizeof(client);
return accept(serverfd, (void *) &client, &len);
}
客户:
int connect_to_server(Config config) {
struct sockaddr_in client;
int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
write(1, "Connecting Jack...\n", strlen("Connecting Jack...\n"));
if (sockfd < 0) {
write(1, "Error creating the socket\n", strlen("Error creating the socket\n"));
return -1;
}
memset(&client, 0, sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons(config.port_jack);
if (inet_aton(config.ip_jack, &client.sin_addr) == 0) {
write(1, "Invalid IP address\n", strlen("Invalid IP address\n"));
return -1;
}
if (connect(sockfd, (void *) &client, sizeof(client)) < 0) {
write(1, "Error connecting to Jack\n", strlen("Error connecting to Jack\n"));
return -1;
}
return sockfd;
}
我可以保证连接正常
【问题讨论】:
-
如果你从
read收到错误返回,即-1返回... -
另外,在发送函数中,
strncpy的合法案例很少见,而不是strcpy后跟循环并设置 null... -
当然应该重构为函数(总是接收n字节)
-
您没有显示套接字是如何创建的。请包含minimal reproducible example
-
我编辑了显示套接字创建的代码