C ++从套接字读取未知数量的数据
c++ read unknow amount of data from socket
我在c++
中写了一个简单的tcp/ip
连接client-server
。
这是处理连接的服务器部分
int sockfd, newsockfd;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
int n = 0;
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd < 0){
cout << "Error opening socket" << endl;
exit(1);
}
bzero((char*)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if(bind(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr))<0){
cout << "Error binding" << endl;
exit(1);
}
listen(sockfd,1);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,(struct sockaddr *)&cli_addr, &clilen );
if(newsockfd < 0){
cout << "Error accepting" << endl;
exit(1);
}
bzero(bytes,size_tot);
uint64_t total_bytes_read = 0;
uint64_t total_bytes_to_read = size_tot;
while(total_bytes_read < total_bytes_to_read){
int bytes_read = read(newsockfd,bytes + total_bytes_read,total_bytes_to_read - total_bytes_read);
if(bytes_read == -1){
cout << "error reading "<< endl;
n = -1;
break;
}
total_bytes_read += bytes_read;
}
但是如果我知道要读取的字节总数,这就可以了。如果要读取的数据总量未知怎么办?我该如何修改这段代码?
您询问了如何修复您的 low-level 接收代码。这很简单——只需调用 read
一次,不要使用 while
循环。只要至少可以读取一个字节的数据,对 read
的调用就会 return。对于要读取的字节数,只需传入缓冲区的大小(或者 space 留在其中,如果之前的调用中已经有一些剩余的话)。
您还需要 high-level 协议代码,就像您知道字节数一样。该代码可能需要有所不同。如果你得到的字节块包括你的停止指示,那么处理所有字节直到停止指示并将额外的字节保留在缓冲区中以备下次使用。如果没有,只需再次调用 read
并获得更多字节。
您的协议处理代码应如下所示:
- 调用
read
并向缓冲区添加任意多的字节。 (此处处理错误或正常关闭。)
- 如果缓冲区中的数据不包含停止指示,则转到步骤1。
- 处理直到停止指示的所有字节。
- 从缓冲区中删除已处理的字节,留下任何未处理的字节。
- 转到第 2 步。
此外,如果对方关闭连接,您在问题中提供的代码将永远旋转。在这种情况下,read
将 return 归零,您将永远无法从连接中读取更多数据。如果 read
return 为零,你应该跳出循环。
首先,摆脱所有 bzero
电话。我不知道为什么这会一直潜入好人的代码中。零,nada,nicht 需要这个。
其次,您需要以某种方式事先传达传输的大小 - 例如,HTTP 1.1 在 header 中提供此信息 - 或者简单地声明连接一旦完成就关闭数据已传输 - 这将是 HTTP 1.0 模型。
我在c++
中写了一个简单的tcp/ip
连接client-server
。
这是处理连接的服务器部分
int sockfd, newsockfd;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
int n = 0;
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd < 0){
cout << "Error opening socket" << endl;
exit(1);
}
bzero((char*)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if(bind(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr))<0){
cout << "Error binding" << endl;
exit(1);
}
listen(sockfd,1);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,(struct sockaddr *)&cli_addr, &clilen );
if(newsockfd < 0){
cout << "Error accepting" << endl;
exit(1);
}
bzero(bytes,size_tot);
uint64_t total_bytes_read = 0;
uint64_t total_bytes_to_read = size_tot;
while(total_bytes_read < total_bytes_to_read){
int bytes_read = read(newsockfd,bytes + total_bytes_read,total_bytes_to_read - total_bytes_read);
if(bytes_read == -1){
cout << "error reading "<< endl;
n = -1;
break;
}
total_bytes_read += bytes_read;
}
但是如果我知道要读取的字节总数,这就可以了。如果要读取的数据总量未知怎么办?我该如何修改这段代码?
您询问了如何修复您的 low-level 接收代码。这很简单——只需调用 read
一次,不要使用 while
循环。只要至少可以读取一个字节的数据,对 read
的调用就会 return。对于要读取的字节数,只需传入缓冲区的大小(或者 space 留在其中,如果之前的调用中已经有一些剩余的话)。
您还需要 high-level 协议代码,就像您知道字节数一样。该代码可能需要有所不同。如果你得到的字节块包括你的停止指示,那么处理所有字节直到停止指示并将额外的字节保留在缓冲区中以备下次使用。如果没有,只需再次调用 read
并获得更多字节。
您的协议处理代码应如下所示:
- 调用
read
并向缓冲区添加任意多的字节。 (此处处理错误或正常关闭。) - 如果缓冲区中的数据不包含停止指示,则转到步骤1。
- 处理直到停止指示的所有字节。
- 从缓冲区中删除已处理的字节,留下任何未处理的字节。
- 转到第 2 步。
此外,如果对方关闭连接,您在问题中提供的代码将永远旋转。在这种情况下,read
将 return 归零,您将永远无法从连接中读取更多数据。如果 read
return 为零,你应该跳出循环。
首先,摆脱所有 bzero
电话。我不知道为什么这会一直潜入好人的代码中。零,nada,nicht 需要这个。
其次,您需要以某种方式事先传达传输的大小 - 例如,HTTP 1.1 在 header 中提供此信息 - 或者简单地声明连接一旦完成就关闭数据已传输 - 这将是 HTTP 1.0 模型。