从插座读取直到我得到足够的字节
我正在尝试阅读一个整数,该整数将使服务器知道消息长度。我会阅读,直到使用while循环到达sizeof(int)
字节。我正在遵循同一惯例的惯例和长度使用段循环多次调用RECV。如果我要做的就是阅读int,我可以直接致电recv并期待所有字节吗?
如果没有,那么我应该如何使用一段时间循环在整数中读取。
struct CONN_STAT {
int size; // length function should return the length into this field
int nRecv; // bytes sent of message
int nSent; // bytes received of message
int lRecv; // bytes received of length
int lSent; // bytes received of length
};
服务器:我如何读取长度
我从消息函数中复制逻辑,它读取的逻辑与此相似 但是信息被一个char数组替换,而(info + pstat-> lrecv)为此作用着它
int readLength(int sockfd, int * info, struct CONN_STAT * pStat){
int infoSize = sizeof(int);
// I copied the logic from my message function it reads similar to this
// but info is replaces by a char array and the (info + pStat->lRecv) works for
while(pStat->lRecv < infoSize){
int n = recv(sockfd, info + pStat->lRecv, infoSize - pStat->lRecv, 0);
if (n > 0) {
pStat->lRecv += n;
}
else if (n == 0 || (n < 0 && errno == ECONNRESET)) {
close(sockfd);
return -1;
}else if (n < 0 && (errno == EWOULDBLOCK)) {
//The socket becomes non-readable. Exit now to prevent blocking.
//OS will notify us when we can read
return 0;
}else {
printf("Unexpected recv error.");
}
}
return 0;
}
像此错误一样称呼它
readLength(sockfd, (int*)pStat->size, pStat);
:警告:从较小的整数类型'int'[-wint to-wint-to-pointer)施放到'int *' -投掷]
I'm trying to read in an integer which is going to let the server know the message length. I read until I reach sizeof(int)
bytes using a while loop. I'm following the same convention for the message and length using a while loop to call recv multiple times. If all I'm doing is reading a int can I just call recv directly and expect all the bytes?
If not then how should I read in a integer using a while loop.
struct CONN_STAT {
int size; // length function should return the length into this field
int nRecv; // bytes sent of message
int nSent; // bytes received of message
int lRecv; // bytes received of length
int lSent; // bytes received of length
};
server : How I'm reading length
I copied the logic from my message function it reads similar to this
but info is replaced by a char array and the (info + pStat->lRecv) works for it
int readLength(int sockfd, int * info, struct CONN_STAT * pStat){
int infoSize = sizeof(int);
// I copied the logic from my message function it reads similar to this
// but info is replaces by a char array and the (info + pStat->lRecv) works for
while(pStat->lRecv < infoSize){
int n = recv(sockfd, info + pStat->lRecv, infoSize - pStat->lRecv, 0);
if (n > 0) {
pStat->lRecv += n;
}
else if (n == 0 || (n < 0 && errno == ECONNRESET)) {
close(sockfd);
return -1;
}else if (n < 0 && (errno == EWOULDBLOCK)) {
//The socket becomes non-readable. Exit now to prevent blocking.
//OS will notify us when we can read
return 0;
}else {
printf("Unexpected recv error.");
}
}
return 0;
}
Calling it like this
readLength(sockfd, (int*)pStat->size, pStat);
error: warning: cast to 'int *' from smaller integer type 'int' [-Wint-to-pointer-cast]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
一般来说,不。 TCP是A byte-streaming 协议,因此,它不能保证任何一个呼叫
recv()
将传递多少个字节。完全有可能(因此,如果有足够的时间,不可避免的),您将recv()
仅来自给定的recv()
呼叫,而整数的第一部分和您需要将收到的字节保存到某个地方的缓冲区中,并计划以后将其余的字节附加到该缓冲区。您只能在收集用来表示它的整个字节后实际分析/使用收到的整数。几乎与您(大概)在整数之后的数据付费中读取的方式几乎相同:将任何接收的字节写入数组中,直到数组中具有解析其所需的字节数为止。 (在这种情况下,您需要在数组中具有
sizeof(int)
字节,然后才能将整数读为整数...并且不要忘记sizeof(int)< /代码>在不同的计算机上可能是一个不同的值,并且
int
可以以大型或小型形式表示。而不是int
和htonl()
和ntohl()
处理任何必要的endian-contression),因为您使用了非块/o,我建议将您的收集撤离器放入
conn_stat
struct,以便给定调用readlength()
可以使用任何接收到的字节更新数组,然后再进行后续。呼叫可以更新数组,依此类推。我想到的方式就是将其视为接收两个数据缓冲器:我可以假设的第一个缓冲区的大小 - 始终是
sizeof(int)
bytes长。第二个缓冲区我将在收到整个第一个缓冲区并可以阅读包含的内容后立即知道。因此,我可以在两个缓冲区中使用(几乎)相同的逻辑,然后根据需要重复。Generally speaking, no. TCP is a byte-streaming protocol, so it doesn't guarantee anything about how many bytes will be delivered by any one call to
recv()
. It's entirely possible (and therefore, given enough time, inevitable) that you'llrecv()
only the first part of the integer from a givenrecv()
call, and you'll need to save the bytes you've received into a buffer somewhere and plan to append the rest of the bytes to that buffer later on. You can only actually parse/use the received integer after you've collected the whole set of bytes that were used to represent it.Pretty much the same way you are (presumably) reading in the data-payload that follows the integer: write any received bytes into an array until the array has the number of bytes in it that are required to parse it. (In this case, you need to have
sizeof(int)
bytes in your array before you can read the integer as an integer... and don't forget thatsizeof(int)
may be a different value on different machines, and that anint
may be represented in either big-endian or little-endian form. You might want to useint32_t
instead ofint
, andhtonl()
andntohl()
to handle any necessary endian-conversion)Since you're using non-blocking I/O, I suggest putting your collection-buffer into the
CONN_STAT
struct, so that a given call toreadLength()
can update the array with any received bytes and then a subsequent call can update the array some more, and so on.The way I think about is to just see it as receiving two data-buffers: The first buffer I can assume the size of -- it will always be
sizeof(int)
bytes long. The second buffer I will know the size of as soon as I have received the entire first buffer and can read what it contains. So I can use (almost) the same logic for both of the two buffers, and then repeat as necessary.