代理服务器正在丢弃数据包
Proxy server dropping packets
所以我一直在写一个代理服务器(遵循Beej的网络编程指南),现在我偶然发现了一个问题,似乎我无法解决。。快把我逼疯了。。
问题是,当它将数据包转发到网络客户端时,由于"对等方重置连接",它会丢弃一些数据包。
这是完整的代码。
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <string>
#include <unistd.h>
using namespace std;
string replace_string(string str, const string from, const string to) {
size_t start_pos = str.find(from);
if(start_pos == string::npos)
return str;
str.replace(start_pos, from.length(), to);
return str;
}
void sigchld_handler(int s)
{
while(waitpid(-1, NULL, WNOHANG) > 0);
}
class Server
{
private:
string PORT;
int MAXDATASIZE;
public:
Server()
{
PORT = "3490";
MAXDATASIZE = 4096;
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int start_server()
{
// first, load up address structs with getaddrinfo():
int socketfd, new_socketfd;
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr;
socklen_t their_addr_size, addr_size;
struct sigaction sa;
char s[INET6_ADDRSTRLEN];
int rv;
int yes = 1;
int BACKLOG = 10;
int numbytes;
unsigned char buf[MAXDATASIZE];
memset(&hints, 0, sizeof hints); // Make sure it is cleared
hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
hints.ai_socktype = SOCK_STREAM; // TCP socket
hints.ai_flags = AI_PASSIVE; // fill in my IP for me
if ((rv = getaddrinfo(NULL, PORT.c_str(), &hints, &servinfo)) != 0) {
cerr << "getaddrinfo: " << gai_strerror(rv) << endl;
return -1;
}
// make a socket, bind it asap
for(p = servinfo; p != NULL; p = p->ai_next)
{
if ((socketfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
//perror("server: socket");
cerr << "ERROR: Server: socket" << endl;
continue;
}
if (setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int)) == -1) {
//perror("setsockopt");
cerr << "ERROR: setsockopt" << endl;
exit(1);
}
if (bind(socketfd, p->ai_addr, p->ai_addrlen) == -1) {
close(socketfd);
//perror("server: bind");
cerr << "ERROR: server: bind" << endl;
continue;
}
break;
}
//If the binding failed
if ( p == NULL)
{
cerr << "Server: failed to bind" << endl;
return -1;
}
//Free space, we do not need it anymore.
freeaddrinfo(servinfo);
//Listen to the socket (port)
if ( listen(socketfd, BACKLOG) == -1)
{
cerr << "ERROR: listen" << endl;
}
// killing zombie processs (all dead processes)
sa.sa_handler = sigchld_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
cout << "Server: waiting for connections ...n"<<endl;
//Main loop
for(;;)
{
their_addr_size = sizeof their_addr;
//Create a new socket when we got a connection
if ((new_socketfd = accept(socketfd, (struct sockaddr *)&their_addr, &their_addr_size))== -1) {
continue;
}
//Converts IP address to 127.0.0.1 (or IPv6 format..) format instead of binary
inet_ntop(their_addr.ss_family,get_in_addr((struct sockaddr *)&their_addr), s, sizeof s);
if ((numbytes = recv(new_socketfd, buf, MAXDATASIZE-1, 0)) == -1) {
cerr << "ERROR: Failed to receive from user-agent" << endl;
exit(1);
}
else
{
/*Parse the header and change some things.*/
string buffer_str(reinterpret_cast<char*>(buf), MAXDATASIZE); // Convert to unsigned char array to make it easier to handle
buffer_str = replace_string(buffer_str, "Proxy-Connection: keep-alive","Connection: close"); // Make it connection Close instead of Keep-Alive
buffer_str = replace_string(buffer_str, "Connection: keep-alive","Connection: close"); // Make it connection Close instead of Keep-Alive
// removes host from GET, and saves it
int first = buffer_str.find_first_of("/");
int last = buffer_str.find_first_of("/", first+2);
int size_of_buf=buffer_str.size();
unsigned char host_request[MAXDATASIZE];
for (int a=0;a<=size_of_buf;a++)
host_request[a]=buffer_str[a];
host_request[size_of_buf]=' ';
string host_name = "";
for(int i=first+2;i<last;++i)
host_name += buffer_str[i];
buffer_str.erase(4, buffer_str.find_first_of("/", first+2)-4);
/*Set up the socket for the proxy-host */
int host_sockfd, host_numbytes;
unsigned char host_buf[MAXDATASIZE];
struct addrinfo host_hints, *host_servinfo, *host_p;
int host_rv;
char host_s[INET6_ADDRSTRLEN];
memset(&host_hints, 0, sizeof(host_hints));
host_hints.ai_family = AF_UNSPEC;
host_hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(host_name.c_str(), "80", &host_hints, &host_servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %sn", gai_strerror(rv));
return 1;
}
// loop through all the results and connect to the first we can
for(host_p = host_servinfo; host_p != NULL; host_p = host_p->ai_next) {
if ((host_sockfd = socket(host_p->ai_family, host_p->ai_socktype,
host_p->ai_protocol)) == -1) {
perror("client: socket");
continue;
}
if (connect(host_sockfd, host_p->ai_addr, host_p->ai_addrlen) == -1) {
close(host_sockfd);
perror("client: connect");
continue;
}
break;
}
if (host_p == NULL) {
fprintf(stderr, "client: failed to connectn");
return 2;
}
inet_ntop(host_p->ai_family, get_in_addr((struct sockaddr *)host_p->ai_addr),s, sizeof s); //Converts the IP address from binary to IPv4/6-format
//printf("client: connecting to %sn", s);
freeaddrinfo(host_servinfo); // all done with this structure
/*Send the GET request to the server*/
send_message(host_sockfd, host_request, sizeof(host_request), "Webserver");
if (!fork())
{
memset(&host_buf, 0, MAXDATASIZE);
while (recv(host_sockfd, &host_buf, MAXDATASIZE, 0) > 0 ) {
close(socketfd);
send_message(new_socketfd, (unsigned char *)host_buf, MAXDATASIZE, "Browser");
memset(&host_buf, 0, MAXDATASIZE);
}
}
close(host_sockfd);
}
//cout << "server: got connection from " << s << endl;
close(new_socketfd); // parent doesn't need this
}
return 1;
}
int send_message(int &socket,unsigned char msg[], int length, string too)
{
usleep(10);
if (send(socket, msg, length, 0) == -1)
{
cerr << "ERROR: sending to " << too << endl;
cerr << "We will lose a packet due to" << endl;
perror("send");
cerr << "-------------------MEDDELANDE-------------------nn" << msg << endl <<
"--------------------------------------------------nn";
return -1;
}
return 1;
}
};
int main()
{
Server srv;
srv.start_server();
}
有什么想法吗?提前感谢!
代码看起来不像我记忆中的Beejs指南。C++不是我的强项,但对我来说,你似乎没有跟踪从套接字写入或读取的数据量。难怪数据不见了。
你的while(为什么?)里面有一个close(),send_message(发送消息)里面有sleep()等等。每当你发现自己为了让事情稍微运转一点而睡()时,通常都是一个bug。
编辑:为了更有建设性,我建议您复制Beejs指南中的sendall()。跟踪recv()给你的数据量,并用sendall发送。
为了提高速度,可以跟踪接收和发送的数据量,并缓冲一些数据,这样就不会阻止等待发送缓冲区可用。
EDIT2:同时向子进程添加一个出口。现在,当使用recv&发送循环。看起来你是想让它留在if(!fork())
里面,但现在不是。
在这里的一些人的帮助下,我已经解决了这个问题!
我必须更改的第一件事是在recv()中用strlen
交换sizeof
。
其次,我没有存储recv收到的数据的大小,所以当我将收到的数据从网络服务器转发到网络浏览器时,我说数据包包含MAXDATASIZE
。解决这个问题的方法是存储接收到的数据,然后在send()
中给出该大小作为参数
最后,我不得不将所有未签名的字符都改为只有字符。
感谢所有帮助我找到这个解决方案的人!特别是修维拉!
相关文章:
- boost::asio UDP 广播客户端仅接收"fast"数据包
- 如何使用发送数据包所花费的时间计算两个节点之间的距离?
- 发送固定大小的 UDP 数据包
- pcap_handler回调仅在使用 NPCAP v0.9991 时包含空数据包
- 在 c++ 中解析数据包数据的最佳方法是什么?
- 接受函数在发送数据包时等待
- 如何在 omnet++ 中发送自定义数据包?
- 数据包访问实践
- 在C++中创建一个简单的数据包路由器,如何跟踪"客户端"?
- 德拉吉诺 LG01-S 收到异常数据包并停止工作
- 将数据包从C++服务器发送到NodeJs服务器时出现MessagePack解码错误
- 使用C++将UDP数据包存储在Structure中
- 可视化 将 TCP 服务器数据包保存到 C++ 中的文件
- C++服务器未显示数据包
- 服务器未收到UDP数据包,花费数小时试图找出问题所在
- MySQL Windows c api 命名管道错误:"在'等待初始通信数据包'时丢失与 MySQL 服务器的连接,系统错误:0
- C++TCP Winsock服务器多次接收相同的数据包
- C# 或 C/C++ 如何从客户端接收数据包,过滤并将它们重定向到服务器,从服务器接收并发送到客户端
- 客户端和服务器之间UDP数据包连续流的问题
- 代理服务器正在丢弃数据包