如何读取套接字编程(c ++)中的所有数据?
How to read all the data in socket programming (c++)?
我正在学习C++套接字编程。我已经通过 10 的缓冲区值初始化。我使用 select(( 函数来监视套接字。当客户端发送的数据大于我的缓冲区可以容纳的数据时,它将读取缓冲区大小的数据,并将再次遍历我的所有客户端并读取剩余数据。如何一次读取所有数据而不再次解析循环以读取剩余数据?
谢谢你的帮助。
for(i = 0;i < max_clients; i++){
sd = clients_list[i];
if(FD_ISSET(sd,&temp)){
char buf[10];
int n = recv(sd, buf, sizeof(buf),0);
if(n == -1){
perror("recv");
}else if(n == 0){
cout << "Client is GONE " << endl;
close(sd);
clients_list[i] = 0;
}
else{
buf[n] = ' ';
cout << "From the node: " << buf << endl;
}
}
}
只是为了完成我的评论 - 这个代码片段可能有助于理解
未测试的代码
for (i = 0;i < max_clients; i++) {
sd = clients_list[i];
if (FD_ISSET(sd,&temp)) {
char buf[10];
int n;
int flag;
do {
n = recv(sd, buf, sizeof(buf),0);
if (n > 0) {
buf[n] = ' ';
cout << "From the node: " << buf << endl;
ioctl(sd, FIONREAD, &flag);
} else {
flag = 0;
}
} while (flag > 0);
if (n < 0) {
perror("recv");
// in case of an error you may actively close the socket
// and end transmission by server
close(sd);
clients_list[i] = 0;
} else {
cout << "Client has currently no further transmission " << endl;
// don't close socket maybe later new transmission
// active close socket by server process only if
// e.g. a timeout has reached
}
}
}
据我所知,您无法确定另一方发送的缓冲区大小。我认为你的方式是最好的处理方式,但你总是可以使用一些技巧。 1. 确定将作为常量发送的缓冲区大小,因此您每次都可能获得所需的数量。 2.我认为最好的方法:使用自制协议来确定发送的消息的长度。例如,您可以读取前 4 个字节以确定消息的大小,然后按给定大小从缓冲区读取数据。
您可以使用下一个转换:
char* c = new char[4];
recv(sd, c, sizeof(c), 0);
int len = (*(int*)c);
delete[] c;
char* but = new char[len];
recv(sd, but, len, 0);
首先,网络是不可靠和不可预测的,所以我们无法知道我们将收到多少字节,这是设计服务器的起点。
其次,我认为如果你想要一个更优雅的服务器,你可能想尝试 epoll 或 IOCP,它们仍然有循环,但 I/O 多路复用性能要好得多。
第三,如果你想接受所有的数据,你可以尝试构造一个缓冲区。在真实网络中,我们总是使用 kafka 或其他一些应用程序缓冲数据。
如何在不解析循环的情况下一次读取所有数据 再次读取剩余数据?
一般来说,您不能,因为所有数据可能还不可用。 如果需要,您可以告诉recv()
阻止直到sizeof(buf)
字节可用,方法是传入MSG_WAITALL
而不是0
到其最终("标志"(参数...但请注意,即使这样,在某些情况下,recv()
也可能返回少于sizeof(buf)
个字节(例如,如果捕获信号,或者在接收sizeof(buf)
字节之前关闭连接,等等(。 因此,即使您使用MSG_WAITALL
您仍然希望实现短读取处理逻辑以获得 100% 正确的行为。
另请注意,发送方没有义务及时发送您期望的所有字节,网络也没有义务及时发送所有字节。 因此,发送方完全有可能向您发送sizeof(buf)-1
字节,然后在发送最后一个字节之前等待 15 分钟,如果您在等待最后一个字节的recv()
调用中被阻止,那么您的服务器将在这么长时间内对所有其他客户端无响应。
因此,在实现这样的多路复用/单线程服务器时,通常最好将套接字设置为非阻塞模式,并为每个客户端的套接字保留单独的接收数据缓冲区。 这样,您可以遍历套接字列表,从每个套接字recv()
尽可能多的数据(不阻塞(,并将该数据附加到该套接字的关联缓冲区,然后检查缓冲区以查看其中是否有足够的数据来处理下一个块,如果这样做,则处理块,然后从缓冲区中删除数据, 并继续。 这样,客户端 B 就不必等待客户端 A 完成向服务器发送消息。
我已经将ioctl((函数与FIONREAD一起使用,以检查是否有更多数据可以读取它,并且它一直在工作。
这是代码:
for(i = 0;i < max_clients; i++){
sd = clients_list[i];
if(FD_ISSET(sd,&temp)){
receive_more:
char buf[10];
int arg = 0;
int n = recv(sd, buf, sizeof(buf),0);
if(n == -1){
perror("recv");
}else if(n == 0){
cout << "Client is GONE " << endl;
close(sd);
clients_list[i] = 0;
}
else{
buf[n] = ' ';
cout << "From the node: " << buf << endl;
ioctl(sd,FIONREAD,&arg);
if(arg > 0){
goto receive_more;
}
}
}
}
- 我们可以在套接字编程中将自定义数据作为辅助数据发送吗?
- 如何读取套接字编程(c ++)中的所有数据?
- 面临在 if 语句之外打印变量数据的问题 完成使用 Qt 编程
- 使用泛型编程的基本数据结构
- C 编程:在循环时运行 2 并从 loop1 获取数据的随机结果
- 了解 UDP 数据包大小限制的 TCP 数据包大小限制以及它在 boost::asio 编程级别的含义
- 如何使用 c++ 以编程方式读取地理数据
- 编程将原始数据发送到打印机
- 蓝牙可以接收数据,但不能传输数据(用C++进行套接字编程以与Matlab通信)
- Linux套接字编程:读取Sigio的数据
- 接收二进制数据并写入(C++ 中的套接字编程)
- 使用sokcet编程回写期间的数据丢失
- 使用c++套接字编程的最大TCP数据包大小
- 如果我在 Windows 中编程我的深度数据包检测程序,我会错过什么主要的事情
- 在 Windows 的 C++ 中编程数据包阻止程序(基本防火墙)
- Java 编程语言中的数据类型如何映射到本机编程语言(如 C 和 C++)中的数据类型
- UDP 数据报套接字编程,服务器在 JAVA 中,客户端在 C++
- C++数据流编程:使用不同的模板参数互连节点
- C++编程:导航到用户文件以保存每个用户的应用程序数据
- 模板元编程可以用来加密编译时常数数据吗