2014-12-06 127 views
2

我假设对于只有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; 
} 
+0

嗯,我确实编写和编译的C++代码,以便这就是为什么我想我添加了标签C++ – rustyengineer 2014-12-06 16:57:20

+0

这是一个项目的分配和选择是C,C++和Java。我们选择C++ – rustyengineer 2014-12-06 17:02:44

+0

是的,我们很清楚这一点。但我想这就是我们选择的,所以我们必须继续它 – rustyengineer 2014-12-06 17:05:32

回答

1

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); 
} 
+0

感谢您的回复! 1.我注意到,谢谢! 2.我认为这就是我一直在使用我的代码。首先发送消息的大小,然后发送实际消息 3.我不确定你在问什么? 4.我读了阅读手册页http://linux.die.net/man/2/read,它说:“成功时,读取的字节数被返回(零表示文件结束),并且文件位置被这个数字提前“。所以我假设对于attempt_read()我不需要更新缓冲区的位置? – rustyengineer 2014-12-06 16:56:38

+0

不,文件位置是您读取的文件设备。您仍然需要调整自己的缓冲区位置。至于“char buffer [rbytes + 1];”标准C++不会允许它,如果你试图编译这样的代码,你应该会收到一个错误。静态数组是在编译时分配的,所以它的长度需要先知道。如果你想要动态数组,你需要使用new []和delete []操作符或std :: vecor,或者在文本消息的情况下使用std :: string。不,你的代码没有发送消息的大小,你发送的所有内容都是一个字符串。 – Dmitry 2014-12-06 23:20:25

+0

Idk为什么但由于某种原因,我没有得到char buf [rbytes + 1]的编译错误?我将它编译在UNIX服务器上。是的,我想我没有在我的帖子中明确提到,在主函数中,我对这个attempt_write/attempt_read进行了2次调用,第一次发送/接收消息的大小,第二次调用将发送/接收实际的消息。 – rustyengineer 2014-12-08 02:55:42