當我通過 tcp 套接字發送長訊息時,它們會被切斷。它因目的地而異。在我的機器上本地發送和接收時,一切都會過去。在我的服務器上本地發送和接收時,它始終在第 21846 個位元組之后被切斷。從我的機器發送到服務器時,它始終在第 1441 個位元組處被切斷。服務器在斯德哥爾摩,我在英國。當客戶端在 Windows 上并使用 Windows 的網路代碼時,也會出現同樣的問題。
這里客戶端應該發送 29 999 個零和一個空終止符,接收它們并列印它們。當我用 wc 計算它們時,我得到了我收到的實際位元組數。所以這些數字代表了一種雙向傳輸,但從測驗中我可以說這個問題具有相同的單向特性。
據我所知,讀/寫函式正在阻塞,所以問題不在于函式退出之前資料沒有完全到達——手冊頁中描述了一個問題。
我怎樣才能解決這個問題?
轉到底部查看解決方案
這是我用來測驗的代碼:
服務器/main.cpp
#include <filesystem>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include "aes/aes.hpp"
#include "network.hpp"
#include <thread>
using namespace std;
int main()
{
int server_socket = InitServerSocket(26969);
std::cout << "Listening..." << std::endl;
while (true) {
// accept incomming connections - blocking
int client_socket = accept(server_socket, NULL, NULL);
if (client_socket < 0) {
std::cerr << "Unable to accept";
close(server_socket);
return 1;
}
char long_text[30000];
read(client_socket, long_text, 30000);
std::cout << long_text << std::endl;
write(client_socket, long_text, 30000);
close(client_socket);
}
return 0;
}
InitServerSocket():
int InitServerSocket(int port)
{
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(port);
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
int server_socket;
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket < 0) {
perror("Unable to create socket");
_exit(1);
}
int result = bind(
server_socket,
(struct sockaddr*)&server_address,
sizeof(server_address));
if (result < 0) {
perror("Unable to bind");
_exit(1);
}
if (listen(server_socket, 1000) < 0) {
perror("Unable to listen");
_exit(1);
}
return server_socket;
}
客戶端/main.cpp
#include <arpa/inet.h>
#include <iostream>
#include <netdb.h>
#include <string.h>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include "network.hpp"
using namespace std;
int main()
{
int socket = ConnectToHost("70.34.195.74", 26969);
char long_text[30000];
for (int i = 0; i < 30000; i )
long_text[i] = '0';
long_text[29999] = '\0';
write(socket, long_text, 30000);
read(socket, long_text, 30000);
std::cout << long_text << std::endl;
CloseConnection(socket);
return 0;
}
連接到主機():
int ConnectToHost(char* IPAddress, int PortNo)
{
// create a socket
int network_socket; // socket descriptor ~= pointer ~= fd
network_socket = socket(AF_INET, SOCK_STREAM, 0);
// specify a destination address
struct sockaddr_in server_address;
server_address.sin_family = AF_INET; // specify protocol
server_address.sin_port = htons(PortNo); // specify port
// server_address.sin_addr.s_addr = a.s_addr; // specify resolved ip
server_address.sin_addr.s_addr = inet_addr(IPAddress);
// connect
int connection_status = connect(
network_socket,
(struct sockaddr*)&server_address,
sizeof(server_address));
if (connection_status == -1)
std::cout << "Failed to conect to remote host\n";
return network_socket;
}
解決方案:
以下是我為解決問題而撰寫的包裝函式:
int Send(int soc, char* buffer, int size)
{
int ret = -1;
int index = 0;
do {
ret = write(soc, buffer index, size - index);
index = ret;
} while (ret > 0);
if (ret == -1)
return -1;
else
return 1;
};
int Recv(int soc, char* buffer, int size)
{
int ret = -1;
int index = 0;
do {
ret = read(soc, buffer index, size - index);
index = ret;
} while (ret > 0);
if (ret == -1)
return -1;
else
return 1;
};
uj5u.com熱心網友回復:
write(client_socket, long_text, 30000);
無論如何,您無法保證所有 30000 個位元組都被寫入,即使使用阻塞套接字也是如此。您必須檢查write()的回傳值以確定實際寫入的位元組數,然后實作所需的邏輯以重試,剩下要寫入的任何內容,并以這種方式繼續,直到所有 30000 個位元組都寫入套接字。這就是套接字始終作業的方式。
read(socket, long_text, 30000);
同樣的事情,你必須檢查回傳的值。如果套接字只有 100 個位元組的未讀資料在等待,您將獲得這 100 個位元組并read()回傳 100。如果阻塞套接字沒有未讀資料,read()則將阻塞。如果套接字最終接收到一個包含 1 個位元組的資料包,則read()回傳 1,這表示僅讀取了 1 個位元組。
我怎樣才能解決這個問題?
您必須始終檢查每個read()和write()回傳的內容,并相應地進行。如果您需要從套接字讀取或寫入更多資料,請再試一次,然后執行此操作。
所以問題不是在函式退出之前資料沒有完全到達——手冊頁中描述了一個問題。
手冊頁還描述了回傳值的含義read()和write()含義:負值表示錯誤,正值表示實際讀取或寫入的位元組數。只有讀取和寫入常規檔案才能保證讀取或寫入請求的位元組數(除非讀取到達檔案末尾)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/400172.html
