我正在尝试解决一个奇怪的C编程问题。
我正在输入客户端程序的URL,然后将该URL传输到服务器程序。唯一的问题是,当服务器程序收到URL时,它缺少前两个字符。因此,如果网址为http://www.google.com,则服务器报告的内容为“tp://www.google.com。”
奇怪的是,这不是一些部分发送问题。我正在检查发送的字节数,并声称已发送整个消息。问题是,在接收端,它只声称它获得了一小部分数据。接收方报告它收到消息长度-2。这是接收端的代码:
printf("%s \n", "Connected. Receive length of URL to wget.");
if ((messageSize = recv(acceptDescriptor, &urlLength, sizeof (int), 0)) == -1) {
perror("recv URL length");
exit(1);
}
urlSizeInt = atoi(urlLength);
char url[urlSizeInt];
printf("%s %d \n", "urlSizeInt: ", urlSizeInt);
printf("%s \n", "Receive URL to wget.");
if((messageSize = recv(acceptDescriptor, &url, 13, 0)) == -1) {
perror("recv URL");
exit(1);
}
发送代码:
printf("%s \n", "Connected");
//connected to first stepping stone in the chain.
//transfer the length of the URL
if (send(socketDescriptor, urlLengthStr, strlen(urlLengthStr), 0) == -1){
perror("send URL Length");
exit(0);
}
//transfer the URL
printf("%s %d \n", "strenlen(url): ",strlen(url));
printf("%s %s \n", "url: ",url);
int sent;
int totalSent=0;
if((sent=send(socketDescriptor, url, strlen(url), 0))==-1){
perror("send URL");
exit(0);
}
printf("%s %d \n", "sent: ",sent);
Send Output:
Connected
strenlen(url): 13
url: http://www.cs
sent: 13
Receive Output:
Connected. Receive length of URL to wget.
urlSizeInt: 13
Receive URL to wget.
messageSize: 11
URL Received: tp://www.cs
将长度编码为发送字符的代码:
char* url = "http://www.cs";
int urlLength = strlen(url);
char* urlLengthStr;
sprintf(urlLengthStr, "%d", urlLength);
答案 0 :(得分:2)
感谢您发布完整代码。问题在于你发送UrlLength的方式。因为您总是recv
sizeof(int)
个字节,所以您的第一次读取会占用已发送网址的第一个字节。
从头开始 - 假设您没有发送URL长度。
问题:网址是可变长度的。接收器如何知道何时读取它? 解决方案:发送前的长度
这很好,除非你将长度编码为字符串,因为这引入了另一个问题
问题:网址长度可以是可变长度(“1”,“12”,“1234”)。接收器如何知道何时读取它? 解决方案:我们不是来过某个地方......
这种递归问题有两种方法:
解决方案a:将URL长度编码为固定大小的字段。 (您可以发送int的二进制表示,但要注意字节排序问题 - 或者您可以将其编码为固定宽度的ascii字段,例如“00000124”
TX(忽略JimR提到的字节排序问题)
int urlLength = strlen(url);
send(socketDescriptor, &urlLength, sizeof(int), 0)
RX:
int urlLength;
recv(socketDescriptor, &urlLength, sizeof(int), 0)
解决方案b:使用终止字符(通常为null或换行符)来指示URL的结尾。只需读取循环中的字节,直到到达终结符。这也解决了你可能会遇到的“部分recv”问题。
答案 1 :(得分:0)
当您从套接字读取时,您正在读取流而不是文件。 有关编写网络代码的良好指导,请参阅here。
即使发送方可能已经立即发送了所有数据,但这并不能保证您一次看到所有数据。您必须在recv
上循环,并考虑每次呼叫接收的字节数。如果recv
返回0
,则套接字已关闭或出现错误,您将不再收到该套接字的数据。
考虑到这些事情......有点像伪代码,我没有测试过这个,但希望它能给你一个想法:
int expectedLength = readLengthFromSocket( socket, sizeof( int ) );
int bytesRead = 0;
char buffer[expectedLength];
bytesRead = recv( socket, buffer, ... );
runningLength = 0;
if( bytesRead < 1 )
// Socket closed or there was an error, handle that here
else
{ runningLength += bytesRead;
while( runningLength < expectedLength )
{
bytesRead = recv( socket, buffer + runningLength, ... );
if( bytesRead < 1 )
// Socket closed or there was an error, handle that here
break;
else
runningLength += bytesRead;
}
}
请注意,通过网络读取和写入int
,long
,long long
,short
和无符号变体通常需要进行字节交换。读取字节缓冲区不会。
请参阅here以获取解释。