2010-08-11 54 views
1

嘿家伙,这里是我的代码。C++奇怪的套接字数据

int main() { 

    char buffer[BUFSIZE]; 

    // define our address structure, stores our port 
    // and our ip address, and the socket type, etc.. 
    struct sockaddr_in addrinfo; 
    addrinfo.sin_family = AF_INET; 
    addrinfo.sin_port = htons(PORT); 
    addrinfo.sin_addr.s_addr = INADDR_ANY; 


    // create our socket. 
    int sock; 
    if ((sock = socket(addrinfo.sin_family, SOCK_STREAM, 0)) < 0) { 
     cout << "Error in creating the socket."; 
    } 

    // bind our socket to the actual adress we want 
    if (bind(sock, (struct sockaddr*)&addrinfo, sizeof(addrinfo)) != 0) { 
     cout << "Error in binding."; 
    } 

    // open the socket up for listening 
    if (listen(sock, 5) != 0) { 
     cout << "Error in opening listener."; 
    } 
    cout << "Waiting for connections...." << endl; 

    char *msg = "Success! You are connected.\r\n"; 

    // continuously accept new connections.. but no multithreading.. yet 
    while(1) { 

     struct sockaddr_in client_addr; 
     socklen_t sin_size = sizeof(client_addr); 

     if(int client = accept(sock, (struct sockaddr*)&client_addr, &sin_size)) { 
      cout << "Recived new connection from " << inet_ntoa(client_addr.sin_addr) << endl; 
      send(client, msg, strlen(msg), 0); 
      while(1) { 
       send(client, buffer, recv(client, buffer, BUFSIZE, 0), 0); 

       cout << buffer << endl; 
       strcpy(buffer, ""); 
      } 

     } else { 
      cout << "Error in accepting new connection." << endl; 
     } 

    } 

    close(sock); 
    return 0; 
} 

现在,我很新的插座,我只是那种试图让他们的感觉,但我有与PHP插座一些经验。我在我的linux机器上通过putty使用telnet来测试这个,我不知道是否会导致任何问题,但服务器正在输出一些奇怪的字符,我不知道为什么。我认为这与缓冲区有关,但我不确定。我可以通过telnet发送诸如“hi”之类的东西到服务器,它会输出它们并将它们发回给我,但当我发送诸如“hoobla”之类的东西时,它会启动时髦的字符。任何的意见都将会有帮助!

提前致谢!

回答

16

由于recv不会终止缓冲区,因此会收到垃圾信息。

在下面的代码中的重要部分是:

int num = recv(client,buffer,BUFSIZE,0); 
if (num < 1) break; 

send(client, ">> ", 3, 0);  // <<-- Nice to have. 
send(client, buffer, num, 0); 

buffer[num] = '\0';   // <<-- Really important bit! 

if (buffer[num-1] == '\n')  // <<-- Nice to have. 
    buffer[num-1] = '\0';  // <<-- Nice to have. 

cout << buffer << endl; 

它试图在打印之前将正常终止您的缓冲区,以及如果存在删除尾随换行符(并允许客户端输入区分并回显线条)。

这一个(一个完整的程序)的作品好一点:

using namespace std; 
#include <iostream> 
#include <sys/socket.h> 
#include <arpa/inet.h> 

#define BUFSIZE 1000 
#define PORT 1234 

int main() { 
    char buffer[BUFSIZE]; 

    // define our address structure, stores our port 
    // and our ip address, and the socket type, etc.. 
    struct sockaddr_in addrinfo; 
    addrinfo.sin_family = AF_INET; 
    addrinfo.sin_port = htons(PORT); 
    addrinfo.sin_addr.s_addr = INADDR_ANY; 

    // create our socket. 
    int sock; 
    if ((sock = socket(addrinfo.sin_family, SOCK_STREAM, 0)) < 0) { 
     cout << "Error in creating the socket."; 
     return -1; 
    } 

    // bind our socket to the actual adress we want 
    if (bind(sock, (struct sockaddr*)&addrinfo, sizeof(addrinfo)) != 0) { 
     cout << "Error in binding."; 
     return -1; 
    } 

    // open the socket up for listening 
    if (listen(sock, 5) != 0) { 
     cout << "Error in opening listener."; 
     return -1; 
    } 

    char *msg = "Success! You are connected.\r\n"; 

    // continuously accept new connections.. but no multithreading.. yet 
    while(1) { 
     cout << "Waiting for connections...." << endl; 

     struct sockaddr_in client_addr; 
     socklen_t sin_size = sizeof(client_addr); 

     if(int client = 
      accept(sock, (struct sockaddr*)&client_addr, &sin_size)) 
     { 
      cout << "Recieved new connection from " 
       << inet_ntoa(client_addr.sin_addr) << endl; 
      send(client, msg, strlen(msg), 0); 
      while(1) { 
       int num = recv(client,buffer,BUFSIZE,0); 
       if (num < 1) break; 
       send(client, ">> ", 3, 0); 
       send(client, buffer, num, 0); 

       buffer[num] = '\0'; 
       if (buffer[num-1] == '\n') 
        buffer[num-1] = '\0'; 
       cout << buffer << endl; 
       strcpy(buffer, ""); 
      } 
     } else { 
      cout << "Error in accepting new connection." << endl; 
     } 
    } 
    close(sock); 
    return 0; 
} 

在客户端:

$ telnet 127.0.0.1 1234 
Trying 127.0.0.1... 
Connected to 127.0.0.1. 
Escape character is '^]'. 
Success! You are connected. 
hello 
>> hello 
my name is pax 
>> my name is pax 
and you? 
>> and you? 
<CTRL-D> 
Connection closed by foreign host. 

,并在服务器端:

$ ./testprog 
Waiting for connections.... 
Recived new connection from 127.0.0.1 
hello 
my name is pax 
and you? 
Waiting for connections.... 
+0

好吧,所以recv实际返回它包含的字节大小? – 2010-08-11 05:04:30

+0

是的,或者错误-1或0如果另一端关闭连接,这两个代码在这里均等对待。 – paxdiablo 2010-08-11 05:10:16

1

问题是buffer不能保证包含字符串终止空字符。在您的cout << buffer之前添加行buffer[BUFSIZE-1] = '\0'

更好的是,实际记录收到的字节数,并使用该信息来确定是否覆盖缓冲区。

+0

嗯,我了解你对空字符的看法。但它似乎并没有工作。我仍然得到奇怪的字符输出。我肯定不会用四个字母的字符串溢出我的缓冲区变量var? – 2010-08-11 04:55:31

+1

你需要使用'recv'中的返回值来存储nul字节,否则“hello”后跟另一个“x”的recv将会给你“xello”(加上第五个缓冲区内的任何垃圾是_already_)在这两种情况下都是一个字节(直到结尾))。 – paxdiablo 2010-08-11 08:48:19