Winsock-从C++; 我有一个客户机-服务器应用程序,服务器部分用C++编写(Winsock),客户端部分用java编写。
当从客户端发送数据时,我首先发送它的长度,然后是实际数据。发送长度的代码如下:Winsock-从C++; 我有一个客户机-服务器应用程序,服务器部分用C++编写(Winsock),客户端部分用java编写。,c++,windows,sockets,types,winsock,C++,Windows,Sockets,Types,Winsock,当从客户端发送数据时,我首先发送它的长度,然后是实际数据。发送长度的代码如下: clientSender.print(text.length()); 其中clientSender的类型为PrintWriter 在服务器端,读取此信息的代码是 int iDataLength; if(recv(client, (char *)&iDataLength, sizeof(iDataLength), 0) != SOCKET_ERROR) //do something 我尝试在if中打
clientSender.print(text.length());
其中clientSender
的类型为PrintWriter
在服务器端,读取此信息的代码是
int iDataLength;
if(recv(client, (char *)&iDataLength, sizeof(iDataLength), 0) != SOCKET_ERROR)
//do something
我尝试在if
中打印iDataLength
的值,结果总是某个随机大整数。如果我将iDataLength
的类型更改为char
,则会得到正确的值。但是,实际值可能远远超过char
的容量
< C++中正确读取一个整数的方法是什么? 你确定循环数不是问题吗?(可能Java将其编码为big-endian,而您将其读取为little-endian)
此外,您可能需要实现
receival
功能(类似于sendall
-as)。确保您收到指定的确切字节数-因为recv
接收的字节数可能比它被告知的要少。您确定endianness不是问题所在吗?(可能Java将其编码为big-endian,而您将其读取为little-endian)
此外,您可能需要实现
receival
功能(类似于sendall
-as)。确保您收到指定的确切字节数-因为recv
收到的字节数可能比它被告知的要少。我认为问题在于PrintWriter正在写入文本,而您正在尝试读取二进制数
以下是PrintWriter对其发送的整数所做的操作:
打印一个整数。string.valueOf(int)生成的字符串为
根据平台的默认字符转换为字节
编码,这些字节完全按照
write(int)方法
试着这样做:
#include <sys/socket.h>
#include <cstring> // for std::strerror()
// ... stuff
char buf[1024]; // buffer to receive text
int len;
if((len = recv(client, buf, sizeof(buf), 0)) == -1)
{
std::cerr << "ERROR: " << std::strerror(errno) << std::endl;
return 1;
}
std::string s(buf, len);
int iDataLength = std::stoi(s); // convert text back to integer
// use iDataLength here (after sanity checks)
#包括
#包含//用于std::strerror()
// ... 东西
字符buf[1024];//接收文本的缓冲区
内伦;
如果((len=recv(客户机,buf,sizeof(buf),0))=-1)
{
std::cerr我认为问题在于PrintWriter正在写文本,而您正试图读取一个二进制数
以下是PrintWriter对其发送的整数所做的操作:
打印一个整数。string.valueOf(int)生成的字符串为
根据平台的默认字符转换为字节
编码,这些字节完全按照
write(int)方法
试着这样做:
#include <sys/socket.h>
#include <cstring> // for std::strerror()
// ... stuff
char buf[1024]; // buffer to receive text
int len;
if((len = recv(client, buf, sizeof(buf), 0)) == -1)
{
std::cerr << "ERROR: " << std::strerror(errno) << std::endl;
return 1;
}
std::string s(buf, len);
int iDataLength = std::stoi(s); // convert text back to integer
// use iDataLength here (after sanity checks)
#包括
#包含//用于std::strerror()
//…东西
char buf[1024];//用于接收文本的缓冲区
内伦;
如果((len=recv(客户机,buf,sizeof(buf),0))=-1)
{
std::cerr数值和ASCII表示之间存在混淆
在Java中编写clientSender.print(text.length());
实际上是在编写ascii字符串-如果长度为15
,则将发送字符1
(代码ascii0x31
)和5
(代码ascii0x35
)
因此,你必须:
- 以可移植的方式发送二进制长度(C或C++中有<代码> HOT和<代码> Ntoh < /Cord>,但java中不确定)
> P>在java端文本长度之后添加分隔符(新行),并在C++中解码:
char buffer[1024]; // a size big enough to read the packet
int iDataLength, l;
l = recv(client, (char *)&iDataLength, sizeof(iDataLength), 0);
if (l != SOCKET_ERROR) {
buffer[l] = 0;
iDataLength = sscanf(buffer, "%d", &iDataLength);
char *ptr = strchr(buffer, '\n');
if (ptr == NULL) {
// should never happen : peer does not respect protocol
...
}
ptr += 1; // ptr now points after the length
//do something
}
Java部分应该是:clientSender.println(text.length());
编辑:
根据Remy Lebeau的评论,TCP中的发送和读取之间没有1对1关系。recv()可以并且确实返回任意数量的数据,因此不能假设单个recv()将读取整行文本
上面的代码不应该执行简单的recv
,而应该准备好连接多个读取以找到分隔符(留给读者的练习是:-)数值和ASCII表示之间存在混淆
在Java中编写clientSender.print(text.length());
实际上是在编写ascii字符串-如果长度为15
,则将发送字符1
(代码ascii0x31
)和5
(代码ascii0x35
)
因此,你必须:
- 以可移植的方式发送二进制长度(C或C++中有<代码> HOT和<代码> Ntoh < /Cord>,但java中不确定)
> P>在java端文本长度之后添加分隔符(新行),并在C++中解码:
char buffer[1024]; // a size big enough to read the packet
int iDataLength, l;
l = recv(client, (char *)&iDataLength, sizeof(iDataLength), 0);
if (l != SOCKET_ERROR) {
buffer[l] = 0;
iDataLength = sscanf(buffer, "%d", &iDataLength);
char *ptr = strchr(buffer, '\n');
if (ptr == NULL) {
// should never happen : peer does not respect protocol
...
}
ptr += 1; // ptr now points after the length
//do something
}
Java部分应该是:clientSender.println(text.length());
编辑:
根据Remy Lebeau的评论,TCP中的发送和读取之间没有1对1关系。recv()可以并且确实返回任意数量的数据,因此不能假设单个recv()将读取整行文本
上面的代码不应该执行简单的recv
,而是准备好连接多个读取以找到分隔符(留给读者的练习:-))简单解释-使用具有明确的逐字节表示的协议,以便使endianness、alignment、delivery等不相关且始终有效。我认为您正在尝试将数字的文本表示形式直接转换为int
。可能将其读入字符缓冲区,然后使用类似std::stoi()的内容
。以下是PrintWriter
对您的int
所做的操作:“由string.valueOf(int)生成的字符串被转换为字节”。您需要将其从platform endian转换为network endian。然后,您需要确保您发送的任何数据在另一端的大小相同。在这里,您可以将其转换回platform endian。这并不像看上去那么简单。最好使用类似JSON的文本协议。简单解释-使用具有明确逐字节表示的协议,以便dianness、校准、交付