通过套接字发送和接收字符串的子函数
我假设对于只有1字节(字符)的消息,我将直接使用read()和write()。通过套接字发送和接收字符串的子函数
对于那些大小大于1字节的消息,我使用两个子函数来读写套接字。
例如,我有服务器构造一个名为strcities(城市列表)的字符串并将其打印出来 - >没有什么奇怪的。然后将该字符串的字节数发送到客户端,然后发送实际的字符串。
客户端首先会读取字节数,然后是实际的城市列表。
出于某种原因,我的代码有时可以工作,有时不会。如果它有效,它还会打印出一些额外的字符,我不知道它们来自哪里。如果没有,它会挂起并永远在客户端等待,而服务器则返回到循环的顶部并等待来自客户端的下一个命令。你能否看看我的代码下面,让我知道我做错了什么?
Attempt_read
string attempt_read(int rbytes) { // rbytes = number of bytes of message to be read
int count1, bytes_read;
char buffer[rbytes+1];
bool notdone = true;
count1 = read(sd, buffer, rbytes);
while (notdone) {
if (count1 == -1){
perror("Error on write call");
exit(1);
}
else if (count1 < rbytes) {
rbytes = rbytes - count1; // update remaining bytes to be read
count1 = read(sd, buffer, rbytes);
}
else {notdone = false;}
} // end while
string returnme;
returnme = string(buffer);
return returnme;
}
Attempt_write
void attempt_write(string input1, int wbytes) { // wbytes = number of bytes of message
int count1;
bool notdone = true;
count1 = write(sd, input1.c_str(), wbytes);
while (notdone) {
if (count1 == -1){
perror("Error on write call");
exit(1);
}
else if (count1 < wbytes) {
wbytes = wbytes - count1;
count1 = write(sd, input1.c_str(), wbytes);
}
else {notdone = false;}
} // end while
return;
}
1)串类有一个方法大小(),将返回字符串的长度,所以你实际上并不需要第二个attempt_write参数。
2)你可以在消息前传送消息的长度,或者你可以在传送一个终止0之后,如果你只发送一个ASCII字符串。由于您的连接可能随时终止,因此最好在发送字符串之前发送准确的长度,以便您的客户知道,期望什么。 3)你使用什么编译器,这将允许字符缓冲区[rbytes + 1]; ?标准的C++需要char buffer = new char [rbytes + 1];并进行相应的删除以避免内存泄漏。
4)在您的代码中,第二次读取函数调用使用相同的缓冲区而不调整长度,所以您实际上会覆盖已接收的数据,并且只有在所有数据都将以第一个函数呼叫。这同样适用于写功能
我建议是这样的:
void data_read(unsigned char * buffer, int size) {
int readed, total = 0;
do {
readed = read(sd, buffer + total, size - total);
if (-1 == writted) {
perror("Error on read call");
exit(1);
}
total += readed;
} while (total < size);
}
string attempt_read() {
int size = 0;
data_read((unsigned char *) &size, sizeof(int));
string output(size, (char) 0x0);
data_read((unsigned char *) output.c_str(), size);
return output;
}
void data_write(unsigned char * buffer, int size) {
int writted, total = 0;
do {
writted = write(sd, buffer + total, size - total);
if (-1 == writted) {
perror("Error on write call");
exit(1);
}
total += writted;
} while (total < size);
}
void attempt_write(string input) {
int size = input.size();
data_write((unsigned char *) &size, sizeof(int));
data_write((unsigned char *) input.c_str(), size);
}
感谢您的回复! 1.我注意到,谢谢! 2.我认为这就是我一直在使用我的代码。首先发送消息的大小,然后发送实际消息 3.我不确定你在问什么? 4.我读了阅读手册页http://linux.die.net/man/2/read,它说:“成功时,读取的字节数被返回(零表示文件结束),并且文件位置被这个数字提前“。所以我假设对于attempt_read()我不需要更新缓冲区的位置? – rustyengineer 2014-12-06 16:56:38
不,文件位置是您读取的文件设备。您仍然需要调整自己的缓冲区位置。至于“char buffer [rbytes + 1];”标准C++不会允许它,如果你试图编译这样的代码,你应该会收到一个错误。静态数组是在编译时分配的,所以它的长度需要先知道。如果你想要动态数组,你需要使用new []和delete []操作符或std :: vecor,或者在文本消息的情况下使用std :: string。不,你的代码没有发送消息的大小,你发送的所有内容都是一个字符串。 – Dmitry 2014-12-06 23:20:25
Idk为什么但由于某种原因,我没有得到char buf [rbytes + 1]的编译错误?我将它编译在UNIX服务器上。是的,我想我没有在我的帖子中明确提到,在主函数中,我对这个attempt_write/attempt_read进行了2次调用,第一次发送/接收消息的大小,第二次调用将发送/接收实际的消息。 – rustyengineer 2014-12-08 02:55:42
嗯,我确实编写和编译的C++代码,以便这就是为什么我想我添加了标签C++ – rustyengineer 2014-12-06 16:57:20
这是一个项目的分配和选择是C,C++和Java。我们选择C++ – rustyengineer 2014-12-06 17:02:44
是的,我们很清楚这一点。但我想这就是我们选择的,所以我们必须继续它 – rustyengineer 2014-12-06 17:05:32