我是套接字新手,我試圖向服務器發送一條訊息,如果服務器在 5 秒內沒有收到來自客戶端的另一條訊息,則向客戶端發送警告,否則將兩條訊息合并并發送回客戶端。
我正在使用 select,一旦呼叫 select(),服務器就無法接收第二條訊息,它總是超時。
我做錯了什么??
服務器
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <unistd.h>
#define BUF_SIZE 256
char *concat(const char *s1, const char *s2);
int main(int argc, char const *argv[]) {
struct sockaddr_in server, client;
struct timeval tv;
int sock, readSize, fd = 0;
char buf[BUF_SIZE], stringA[BUF_SIZE], stringB[BUF_SIZE];
socklen_t addressSize;
fd_set readfds;
bzero(&server, sizeof(server));
server.sin_family = PF_INET;
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_port = htons(6000);
// TCP check
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock == -1) {
printf("socket: %s\n", strerror(errno));
return 1;
}
// Handle binding error
if (bind(sock, (struct sockaddr *)&server, sizeof(server)) == -1) {
printf("bind: %s\n", strerror(errno));
return 1;
}
// Handle connection error
if (listen(sock, 5) == -1) {
printf("listen: %s\n", strerror(errno));
return 1;
}
// Handle client acceptance error
addressSize = sizeof(client);
sock = accept(sock, (struct sockaddr *)&client, &addressSize);
while ((readSize = recv(sock, stringA, sizeof(stringA), 0))) {
stringA[readSize] = '\0';
printf("Read Message A: %s", stringA);
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
FD_SET(0, &readfds);
tv.tv_sec = 5;
tv.tv_usec = 0;
if (select(sock 1, &readfds, NULL, NULL, &tv) < 0) {
printf("ERROR in select");
}
char *result;
// If more messgae receve within 5 seconds, but the program never reached this part
if (FD_ISSET(sock, &readfds)) {
// Get string B
readSize = recv(sock, stringB, sizeof(stringB), 0);
stringB[readSize] = '\0';
result = concat(stringA, stringB);
printf("Some more input received\n");
} else {
printf("Time out\n");
}
send(sock, &result, sizeof(result), 0);
}
printf("Client has closed the connection.\n");
close(sock);
return 0;
}
char *concat(const char *s1, const char *s2) {
char *result = malloc(strlen(s1) strlen(s2) 1);
strcpy(result, s1);
strcat(result, s2);
return result;
}
客戶
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#define BUF_SIZE 256
int main(int argc, char const *argv[]) {
struct sockaddr_in server;
struct timeval tv;
int sock, readSize, addressSize;
char buf[BUF_SIZE];
bzero(&server, sizeof(server));
server.sin_family = PF_INET;
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_port = htons(6000);
sock = socket(PF_INET, SOCK_STREAM, 0);
addressSize = sizeof(server);
// TCP check
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock == -1) {
printf("socket: %s\n", strerror(errno));
return 1;
}
// Handle connection error
if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == -1) {
printf("connect: %s\n", strerror(errno));
return 1;
}
while (1) {
fgets(buf, 256, stdin);
if (feof(stdin)) break;
send(sock, &buf, sizeof(buf), 0);
readSize = recv(sock, buf, sizeof(buf), 0);
buf[readSize] = '\0';
printf("%s\n", buf);
}
close(sock);
return 0;
}
uj5u.com熱心網友回復:
您要問的問題似乎是客戶端嘗試在每個send(). 這將阻塞,直到它可以讀取至少一個位元組或服務器關閉連接。同時,服務器希望客戶端一個接一個地發送訊息,對奇數訊息沒有任何回應。
這是設計問題的征兆。這個 ...
我正在嘗試向服務器發送訊息,如果服務器在 5 秒內沒有收到來自客戶端的另一條訊息,則向客戶端發送警告,否則合并兩條訊息并發送回客戶端。
... 聽起來很簡單,看似有道理,但實際上既不簡單也不明智。假設您有一個善意的客戶使用您的服務。它知道該服務需要兩條訊息,一條接一條,然后將兩條訊息串聯起來進行回應。為什么這樣的客戶端無法發送預期的第二條訊息?最可能的解釋是
- 它不能,因為它被掛起,因為網路鏈接出現故障,因為它的主機出現故障,或類似的。
- 它沒有,因為它在它可以之前就被殺死了。
- 它沒有,因為它是越野車。
這些都沒有被服務器發送警告訊息所拯救。(但是如果客戶端在傳遞第二條訊息之前被殺死,那么服務器可能會在套接字上看到 EOF 并表示已準備就緒。)
此外,假設客戶端掛起,服務器發送警告,然后客戶端恢復。當它嘗試從服務器讀取預期回應時,它會收到警告訊息,或者很可能將警告與預期回應連接起來。客戶端應該如何區分警告訊息和正常回應?
我建議完全放棄警告。服務器可以改為只是斷開無回應的客戶端。
如果您想保留警告并繼續僅使用一個套接字,那么您需要擴充您的協議以使警告訊息與正常回應區分開來。例如,服務器的回應可能分為兩部分——標識訊息型別的回應代碼,后跟回應正文。
或者,您可以為兩個不同的訊息流使用單獨的套接字,但我認為這比您現在想要處理的要復雜。
但是,您的代碼還有其他問題。主要的是
您似乎假設
send/write和recv/read呼叫將配對,以便一個呼叫從一側發送的資料正是另一側呼叫接收到的資料。這根本不是一個安全的假設。您正在使用面向流的套接字,這種套接字的特征之一是資料流沒有任何內置的訊息邊界。如果要將資料劃分為邏輯上獨立的訊息,則需要將其分層在流之上。您沒有考慮
send/write和recv/read可能(成功)傳輸的位元組數少于您請求的位元組數。一般來說,您需要注意這些函式的回傳值,并準備好使用多次呼叫來傳輸給定傳輸的所有位元組。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/313381.html
下一篇:Ejabberd網路層性能不佳
