【问题标题】:C++ strange socket dataC++ 奇怪的套接字数据
【发布时间】:2011-03-28 04:31:38
【问题描述】:

大家好,这是我的代码。

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”之类的内容时,它会启动时髦的字符内容。任何的意见都将会有帮助!

提前致谢!

【问题讨论】:

    标签: c++ sockets


    【解决方案1】:

    因为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....
    

    【讨论】:

    • 是,或 -1 表示错误或 0 表示另一端关闭连接,代码在这里同等对待。
    【解决方案2】:

    问题是buffer 不能保证包含以字符串结尾的空字符。在 cout &lt;&lt; buffer 之前添加行 buffer[BUFSIZE-1] = '\0'

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

    【讨论】:

    • 嗯,我理解你所说的关于空字符的意思。但这似乎不起作用。我仍然得到奇怪的字符输出。我肯定不会用四个字母的字符串溢出我的缓冲区变量吗?
    • 你需要使用来自recv的返回值来存储nul字节,否则一个“hello”的recv后面跟着另一个“x”会给你“xello”(加上任何垃圾在这两种情况下,已经在缓冲区中超过第五个字节(直到末尾)。
    猜你喜欢
    • 2013-11-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    • 2021-09-25
    • 1970-01-01
    相关资源
    最近更新 更多