将字符串连接到自己的协议中
Concatenating strings into own protocol
我正在用socket.h编写网络程序来学习。我已经编写了服务器和客户端简单的程序,可以使用用户指定的缓冲区大小在它们之间传输文件。
服务器 void transfer(string name)
{
char *data_to_send;
ifstream myFile;
myFile.open(name.c_str(),ios::binary);
if(myFile.is_open))
{
while(myFile.eof))
{
data_to_send = new char [buffer_size];
myFile.read(data_to_send, buffer_size);
send(data_to_send,buffer_size);
delete [] data_to_send;
}
myFile.close();
send("03endtransmission",buffer_size);
}
else
{
send("03error",buffer_size);
}
}
客户void download(string name)
{
char *received_data;
fstream myFile;
myFile.open(name.c_str(),ios::out|ios::binary);
if(myFile.is_open())
{
while(1)
{
received_data = new char[rozmiar_bufora];
if((receivedB = recv(sockfd, received_data, buffer_size,0)) == -1) {
perror("recv");
close(sockfd);
exit(1);
}
if(strcmp(received_data,"03endoftransmission") == 0)
{
cout<<"End of transmission"<<endl;
break;
}
else if (strcmp(received_data,"03error") == 0)
{
cout<<"Error"<<endl;
break;
}
myFile.write(received_data,buffer_size);
}
myFile.close();
}
问题发生了,当我想实现我自己的协议-两个字符(控制),32个字符哈希,其余的包是数据。我尝试了几次将其分割,最后得到以下代码:
服务器#define PAYLOAD 34
void transfer(string name)
{
char hash[] = "12345678901234567890123456789012"; //32 chars
char *data_to_send;
ifstream myFile;
myFile.open(name.c_str(),ios::binary);
if(myFile.is_open))
{
while(myFile.eof))
{
data_to_send = new char [buffer_size-PAYLOAD];
myFile.read(data_to_send, buffer_size-PAYLOAD);
concatenation = new char[buffer_size];
strcpy(concatenation,"02");
strcat(concatenation,hash);
strcat(concatenation,data_to_send);
send(concatenation,buffer_size);
delete [] data_to_send;
delete [] concatenation;
}
myFile.close();
send("03endtransmission",buffer_size);
}
else
{
send("03error",buffer_size);
}
}
客户void download(string name)
{
char *received_data;
fstream myFile;
myFile.open(name.c_str(),ios::out|ios::binary);
if(myFile.is_open())
{
while(1)
{
received_data = new char[buffer_size];
if((receivedB = recv(sockfd, received_data, buffer_size,0)) == -1) {
perror("recv");
close(sockfd);
exit(1);
}
if(strcmp(received_data,"03endoftransmission") == 0)
{
cout<<"End of transmission"<<endl;
break;
}
else if (strcmp(received_data,"03error") == 0)
{
cout<<"Error"<<endl;
break;
}
control = new char[3];
strcpy(control,"");
strncpy(control, received_data,2);
control[2]=' ';
hash = new char[33];
strcpy(hash,"");
strncpy(hash,received_data+2,32);
hash[32]=' ';
data = new char[buffer_size-PAYLOAD+1];
strcpy(data,"");
strncpy(data,received_data+34,buffer_size-PAYLOAD);
myFile.write(data,buffer_size-PAYLOAD);
}
myFile.close();
}
但是这个输入文件一些^@而不是实际数据。在服务器和客户机上向控制台显示"数据"看起来是一样的。如果你知道怎么分的话,我会很感激的。
你有一些问题可能是你的问题,也可能不是。
(1) send/recv
的返回值小于您的请求。你可能要求接收30个字节,但在recv调用中只得到10个字节,所以所有这些都必须在循环中编码并缓冲在某个地方,直到你真正得到你想要的数字。您的第一组程序在这方面很幸运,可能只是因为您在有限的数据上进行了测试。一旦你开始阅读更多的数据,你对你正在阅读(和比较)的假设就会失败。
(2)不需要在循环中一直分配char缓冲区;在循环之前分配它们,或者只使用本地缓冲区而不是堆。你所做的是低效的,在第二个程序中,你有内存泄漏,因为你没有删除它们。
(3)可以去掉strcpy/strncpy语句,只使用memmove()
你的具体问题不是跳到我,但也许这将推动正确的方向。更多的信息是什么被正确传输的,以及你在数据中看到问题的确切位置,将会有所帮助。
但是这个输入文件一些^@而不是实际数据。显示控制台的"data"在服务器和客户机上看起来是一样的。如果你知道怎么做我可以把它分开,我将非常感激。
你说数据(我假设是完整的文件,而不是'^@')在客户端和服务器上是相同的?如果是这种情况,那么您的问题可能是将数据写入文件,而不是数据本身的实际传输。
如果是这种情况,您可能需要检查有关程序如何写入文件的假设-例如,您是传入要写入文件的文本数据,还是二进制数据?如果您正在编写二进制数据,但它使用以NULL结尾的字符串,那么它很可能会提前停止将有效的二进制信息视为NULL。
如果是文本模式,您可能需要考虑将所有带有memset的字符串初始化为默认字符(而不是NULL),以查看它是否被输出为垃圾数据。
如果服务器和客户端都显示'^@'(或任何数据),基于二进制的char数据将与strcpy/strcat函数不兼容,因为这依赖于NULL终止(而-as二进制使用大小终止)。
我无法找到具体的问题,但也许这可以提供一两个有帮助的见解。
- 没有为自己的结构调用列表推回方法
- 在他自己的方法中,有可能将一个对象取消引用到另一个对象吗
- 在c++中为我自己的基于指针的数组分配内存的正确方法
- C++从对象自己的类中删除对象
- 使用 std::optional,而不是自己的结构
- 子轴围绕父轴而不是他自己的轴旋转
- 这个C++编译器优化(在自身的实例上调用对象自己的构造函数)的名称是什么,它是如何工作的?
- C++ 如何为自己的迭代器类从迭代器转换为const_iterator?
- 重载 + 自己的类和 std::string 的运算符
- 类无法访问自己的私有静态 constexpr 方法 - Clang bug?
- 是否可以在不填充自己的参数的情况下将模板函数作为参数传递?
- 如何访问模板参数自己的模板参数?
- 将矩阵乘以我自己的输入的向量
- 您应该在什么时候创建自己的异常类型
- 派生类是从基类继承 v 指针并仅使用它,还是也有自己的 v 指针?
- string1 == string2 和你自己的 for 循环比较有什么区别?
- 如何使用ZeroMQ为协议缓冲区编写自己的RPC实现
- 自己的C++网络协议:如何定义唯一的二进制报文值
- 如何开始编写自己的类 IP 协议
- 将字符串连接到自己的协议中