C UDP RecvFrom最终悬挂在远程连接上
c++ udp recvfrom eventually hangs over remote connection
我正在用C 编写客户端服务器UDP应用程序。当客户端和服务器在同一台计算机上运行时,该应用程序正常工作,但是当我在AWS中的EC2实例上运行客户端时,服务器会收到4个消息,然后开始挂在recvfrom
上。客户端正在以500个字节的块发送文件,服务器将其写入文件。服务器接收每个块后,该服务器将发送ack
。客户端的超时时间为2秒,如果它在超时之前未接收ack
,则它会重新安排上一个块。这是我的客户端代码
void Sender::send_file(const char* host) {
cout << "in send filen";
int sock = 0;
struct sockaddr_in serv_addr;
size_t length = 8;
unsigned char res_buf[8] = {0};
if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
std::cout << "n Socket creation error n";
exit(EXIT_FAILURE);
}
struct timeval tv;
tv.tv_sec = timeout;
tv.tv_usec = 0;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
// copy 0 into serv_addr members
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
serv_addr.sin_addr.s_addr = inet_addr(host);
size_t file_size = buffer.size();
cout << "file size " << to_string(file_size) << "n";
size_t file_pos = 0;
int next_iteration = 1;
bool establish = true;
while(file_pos < file_size - 1) {
cout << "waiting for lockn";
std::unique_lock<std::mutex> lock(mrun);
main_ready.wait(lock, [&next_iteration, this]{return next_iteration == current_iteration; });
lock.unlock();
cout << "acquired lockn";
++next_iteration;
Segment segment;
vector<unsigned char> req_str;
if(!establish) {
if(file_pos + mss < file_size) {
std::vector<unsigned char> file_chunk(buffer.begin() + file_pos, buffer.begin() + file_pos + mss);
segment.data = file_chunk;
file_pos += mss;
}
else {
std::vector<unsigned char> file_chunk(buffer.begin() + file_pos, buffer.end());
segment.data = file_chunk;
file_pos = file_size;
}
segment.seq_num = file_pos - mss;
req_str = segment.to_bytes(false, mss);
}
else {
segment.seq_num = 0;
req_str = segment.to_bytes(true, mss);
}
bool is_ack = false, timed_out = false;
std::chrono::high_resolution_clock::time_point start_time, end_time;
long duration = 0;
unsigned char* req = req_str.data();
size_t num_bytes = req_str.size();
unsigned int len = 0;
while(!is_ack) {
cout << "about to send data " << std::to_string(segment.seq_num) << " bytes " << std::to_string(num_bytes) << "n";
ssize_t send_res = sendto(sock, req, num_bytes, 0, (const struct sockaddr *) &serv_addr, sizeof(serv_addr));
printf("Sent to %s:%dn", inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port));
cout << "send res " << to_string(send_res) << " " << strerror(errno) << "n";
start_time = std::chrono::high_resolution_clock::now();
bzero(res_buf, length);
cout << "about to read ackn";
ssize_t block_sz = recvfrom(sock, res_buf, length, 0, (struct sockaddr *) &serv_addr, &len);
cout << "read ackn";
end_time = std::chrono::high_resolution_clock::now();
duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count();
cout << "block sz " << std::to_string(block_sz) << " duration " << std::to_string(duration) << std::endl;
if(duration > timeout * 1000)
timed_out = true;
if(timed_out || errno == ETIMEDOUT || block_sz < 0) {
std::cout << "time out/error occurred on read " << to_string(errno) << "n";
cout << strerror(errno) << "n";
bzero(res_buf, length);
timed_out = false;
continue;
}
//add_nulls(res_buf);
is_ack = read_response(segment.seq_num, res_buf);
cout << "is ack " << is_ack << "nn";
bzero(res_buf, length);
}
establish = false;
lock.lock();
if(--worker_count == 0) {
lock.unlock();
iteration_complete.notify_one();
}
}
cout << "Out of while loopn";
close(sock);
files_sent.push_back(1);
}
它每次都完全发送508个字节,除了仅10个字节的第一部分。我打印每次迭代后的sendto结果,看起来总是像这样
Sent to 52.0.0.0:7735
send res 508 Undefined error: 0
***更新 ***一旦服务器开始挂在recvfrom
,客户端时间出去等待ack
,客户就会开始不断打印以下错误,因为它会继续重新延伸块。
Sent to 52.0.0.0:7735
send res 508 Resource temporarily unavailable
服务器代码看起来像
void Receiver::download_file() {
int server_fd;
struct sockaddr_in serv_addr, cli_addr;
int segment_size = 20;
umap seg_map;
ACK_Segment::init_static();
std::random_device rd; //Will be used to obtain a seed for the random number engine
std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
std::uniform_real_distribution<> dis(0.0, 1.0);
if((server_fd = socket(AF_INET, SOCK_DGRAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
memset(&serv_addr, 0, sizeof(serv_addr));
memset(&cli_addr, 0, sizeof(cli_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(PORT);
// bind socket to port
//bzero(buffer, segment_size);
ssize_t block_sz = 0;
unsigned int len = sizeof cli_addr;
bool is_set_mss = true;
if(bind(server_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
//unsigned char* buffer = bvec.data();
vector<unsigned char> bvec(segment_size);
unsigned char* buffer = bvec.data();
bool is_resized = false;
while(true) {
cout << "about to recvfromn";
printf("Receiving from %s:%dn", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
cout << "segment size " << to_string(segment_size) << " len " << to_string(len) << "n";
block_sz = recvfrom(server_fd, buffer, segment_size, 0, ( struct sockaddr *) &cli_addr, &len);
cout << "block size " << to_string(block_sz) << "errno " << to_string(errno) << " " << strerror(errno) << "n";
if(block_sz > 0) {
cout << "Received data - bytes " << std::to_string(block_sz) << "n";
printf("Received from %s:%dn", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
double rand_val = dis(gen);
if(is_set_mss) {
seg_map = read_segment(bvec, block_sz, true);
if(seg_map["checksum_valid"] == "true") {
segment_size = mss + HEADER_SIZE;
is_resized = true;
}
}
else {
if(block_sz == 0) {
cout << "received no datan";
break;
}
seg_map = read_segment(bvec, block_sz, false);
}
if(seg_map["checksum_valid"] == "false")
cout << "invalid checksumn";
else if(is_set_mss) {
vector<unsigned char> ack = get_ack();
//remove_nulls(ack);
unsigned char* ack_bytes = ack.data();
cout << "about to send ackn";
sendto(server_fd, ack_bytes, 8, 0, (const struct sockaddr *) &cli_addr, len);
//send(new_socket, ack, 8, 0);
is_set_mss = false;
}
else {
if(seg_map["in_order"] == "true") {
string data = seg_map["data"];
std::ofstream out;
out.open(file_name, std::ios_base::app);
out << data;
out.close();
cout << "Done writing file chunkn";
}
vector<unsigned char> ack = get_ack();
unsigned char* ack_bytes = ack.data();
sendto(server_fd, ack_bytes, 8, 0, (const struct sockaddr *) &cli_addr, len);
}
if(is_resized) {
bvec.resize(segment_size);
is_resized = false;
}
bvec.clear();
buffer = bvec.data();
cout << "Cleared buffernn";
}
cout << "out of inner whilen";
}
}
此打印
Receiving from 168.0.0.0:18832
segment size 508 len 16
block size 508 errno 0 Success
但是,它仅在4次打印,然后在客户端继续发送508字节时挂在recvfrom上,并且该段的大小在recvfrom
中保持在508。为什么Recvfrom会开始工作,然后突然停止?
update
我将其浇水到我可以编写的最简单的UDP客户端服务器,这是客户端:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <vector>
#include <iostream>
#include <cstring>
#include <string>
using std::vector;
using std::cout;
using std::to_string;
int main() {
int sock = 0;
struct sockaddr_in serv_addr;
size_t length = 11;
unsigned char res_buf[11] = {0};
if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
std::cout << "n Socket creation error n";
exit(EXIT_FAILURE);
}
struct timeval tv;
tv.tv_sec = 2;
tv.tv_usec = 0;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
// copy 0 into serv_addr members
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(7735);
serv_addr.sin_addr.s_addr = inet_addr("52.71.240.175");
vector<unsigned char> req(20);
for(int i = 0; i < 20; i++)
req[i] = 'A';
unsigned char* req_str = req.data();
size_t num_bytes = req.size();
unsigned int len = sizeof serv_addr;
while(true) {
cout << "about to send datan";
ssize_t send_res = sendto(sock, req_str, num_bytes, 0, (const struct sockaddr *) &serv_addr, sizeof(serv_addr));
bzero(res_buf, length);
cout << "about to read ackn";
ssize_t block_sz = recvfrom(sock, res_buf, length, 0, (struct sockaddr *) &serv_addr, &len);
cout << "received " << res_buf << "n";
}
}
这是服务器:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <vector>
#include <iostream>
#include <cstring>
#include <string>
using std::vector;
using std::cout;
using std::to_string;
int main() {
int server_fd;
struct sockaddr_in serv_addr, cli_addr;
int segment_size = 20;
memset(&serv_addr, 0, sizeof(serv_addr));
memset(&cli_addr, 0, sizeof(cli_addr));
if((server_fd = socket(AF_INET, SOCK_DGRAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(7735);
unsigned int len = sizeof cli_addr;
if(bind(server_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
vector<unsigned char> bvec(segment_size);
unsigned char* buffer = bvec.data();
while(true) {
cout << "about to receive fromn";
ssize_t block_sz = recvfrom(server_fd, buffer, segment_size, 0, ( struct sockaddr *) &cli_addr, &len);
if(block_sz > 0) {
printf("Received from %s:%dn", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
char* ack_bytes = "ack message";
cout << "about to send ackn";
sendto(server_fd, ack_bytes, 11, 0, (const struct sockaddr *) &cli_addr, len);
}
}
}
发生相同的行为,服务器接收了4条消息,但是在第五封信中,它只是挂在recvfrom
中。我尝试关闭并重新打开服务器上每个迭代的插座,这无效。
我必须在接收到服务器的每个ACK后关闭并重新打开客户端的套接字。我不需要在服务器端关闭并重新打开。我不确定这是否解决了我面临的问题的根本原因,但它允许我的应用程序正确运行。
相关文章:
- 如何在 2 台主机之间保持 UDP 套接字连接打开
- 使用 ssh 重新连接到远程 Ubuntu 机器后,如何继续使用 gdb 调试 c++ 代码?
- C++ Winsock2 客户端未通过远程 IP 连接到服务器
- 使用单个套接字处理多个传入的 UDP 连接
- 使用 IP 帮助程序的 Windows 中活动 UDP 连接的远程地址
- 连接到远程存储库并获取数据
- 连接UDP套接字,但仍然接收来自其他源的数据报
- 接受套接字,但m_socket.远程终结点引发 传输终结点未连接
- 在环路中使用 UDP 套接字时连接被拒绝
- C UDP RecvFrom最终悬挂在远程连接上
- 使用 boost::asio 获取 UDP 套接字远程地址
- 如何从活动的 udp 连接获取远程 IP 地址和端口
- Libssh C 包装器 - 离开范围时基本的远程连接segfaults
- MySQL 服务器不接受远程连接
- C++ Winsock 服务器-客户端远程连接
- mysql 远程连接 - mysql CL 客户端工作,C++应用程序不工作
- 无法连接到服务器(通过远程连接)
- MySQL和Qt远程连接
- 远程连接MySQL是安全的吗?
- C++应用程序如何在不让MySQL服务器接受远程连接的情况下访问远程MySQL数据库