4

我写了一个 html5 客户端和 ac 服务器,当客户端尝试连接到服务器时,似乎从客户端警报消息中,它连接成功(调用 onopen 函数)然后连接被关闭(首先调用 onerror 函数,然后调用 onclose 函数)。客户端关闭连接后,服务器收到 SIGPIPE 信号并退出。

<!DOCTYPE>

<html>
    <head>
        <meta http-equiv="content-type" content="text/html" />
        <title>C Websocket Test</title>

        <script>
            var websocket;
            var wsUri = "ws://localhost:49880";
            //var wsUri = "wss://echo.websocket.org";

            function connect() {
                try {
                    websocket = new WebSocket(wsUri);

                    websocket.onopen = function(msg) {
                        alert('websocket_onopen: connect success');
                    }

                    websocket.onclose = function(msg) {
                        alert('websocket_onclose: status - ' + this.readyState);
                    }

                    websocket.onmessage = function(msg) {
                        alert('server says: ' + msg.data);
                    }

                    websocket.onerror = function(msg) {
                        alert('websocket_onerror: connect error - ' + msg);
                    }
                } catch (E) {
                    alert('try connect error' + E);
                    return;
                }           
            }

            function send() {

                websocket.send('hello, i am websocket client');
            } 

            function close() {
                websocket.close();
            } 
        </script>
    </head>

    <body>
        <input id="msg" type="text">
        <button id="connect" onclick="connect();">Connect</button>
        <button id="send" onclick="send();">Send</button>
        <button id="close" onclick="close();">Close</button>
    </body>

</html>

服务器:

#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
#include <openssl/sha.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>

#define LISTENING_PORT 49880
#define MAXLENGTH 1024 + 1

char *get_websocket_key(char *request, char *buf, size_t buf_len)
{
    size_t len;
    char *key = "Sec-WebSocket-Key:";
    char *end, *start = strstr(request, key);

    start += strlen(key) + 1;
    end = start;

    while (*end != '\n' && *end != '\r') {
        ++end;
    }

    len = end -start;

    if (len >= buf_len)
        return NULL;

    memcpy(buf, start, len);
    buf[len] = '\0';

    return buf;
}

char *base64_encode(const char *data, size_t data_len, char *out, size_t out_len)
{
    FILE *fp;
    int len;

    int fd = open(".base64_src", O_CREAT | O_WRONLY | O_TRUNC);
    if (fd < 0) {
        perror("open");
        return NULL;
    }

    if (write(fd, data, data_len) != data_len) {
        perror("write");
        return NULL;
    }

    close(fd);

    if ( (fp = popen("base64 .base64_src", "r")) == NULL) {
        perror("popen");
        return NULL;
    }

    len = 0;
    while (fgets(out + len, out_len - len, fp) != NULL) {
        len = strlen(out);
        out[--len] = '\0';
    }

    if (out[len - 1] == '\n')
        out[len - 1] = '\0';

    pclose(fp);
    system("rm .base64_src");

    return out;
}

void parsestr(char *request,char *data)
{
    int needle;
    char sec_key[1024], encrypt_key[1024], buf[1024];

    memset(request, 0, sizeof(request));
    get_websocket_key(data, sec_key, sizeof(sec_key));
    //printf("[== original-key]:[%s]\n", sec_key);
    strcat(sec_key, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
    SHA1(sec_key, strlen(sec_key), encrypt_key);
    //printf("[base64_encode]: [%s]\n", base64_encode(encrypt_key, strlen(encrypt_key), sec_key, sizeof(sec_key)));
    base64_encode(encrypt_key, strlen(encrypt_key), sec_key, sizeof(sec_key));
    strcpy(request, "HTTP/1.1 101 Switching Protocols\r\n");
    strcat(request, "Upgrade: websocket\r\n");
    strcat(request, "Connection: Upgrade\r\n");
    sprintf(encrypt_key, "Sec-WebSocket-Accept: %s\r\n", sec_key);
    strcat(request, encrypt_key);
    strcat(request, "\r\n");
}

void sig_handler(int signo)
{
    printf("[Signal Received: %d]\n", signo);
    exit(1);
}

int main(int argc, char *argv[])
{
    int server_fd, len, ret, client_fd;
    int reuse = 1;
    fd_set rwfd;
    struct sockaddr_in s_addr, client_addr;
    struct timeval tv;

    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int));
    if (server_fd < 0)
        perror("socket");

    s_addr.sin_port = htons(LISTENING_PORT);
    s_addr.sin_family = AF_INET;
    s_addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(server_fd, (struct sockaddr *)&s_addr, sizeof(struct sockaddr)) < 0)
        perror("bind");

    if (listen(server_fd, 5) < 0)
        perror("listen");

    len = sizeof(struct sockaddr);
    tv.tv_sec = 5;
    tv.tv_usec = 0;

    signal(SIGPIPE, sig_handler);

    while (1) {
        char buf[MAXLENGTH], request[MAXLENGTH];
        int responsed = 0;

        client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &len);

        if (client_fd < 0) {
            perror("accept");
            continue;
        } else {
            printf("%s connected.\n", inet_ntoa(client_addr.sin_addr));
        }

        while (1) {
            int retval, maxfd;

            FD_ZERO(&rwfd);
            FD_SET(STDIN_FILENO, &rwfd);
            FD_SET(client_fd, &rwfd);

            maxfd = client_fd > STDIN_FILENO ? client_fd : STDIN_FILENO;

            if (select(maxfd + 1, &rwfd, NULL, NULL, &tv) < 0) {
                perror("select");
                continue;
            } else {
                if (FD_ISSET(STDIN_FILENO, &rwfd)) {
                    fgets(buf, MAXLENGTH, stdin);
                    parsestr(request, buf);

                    if (send(client_fd, request, MAXLENGTH, 0) > 0) 
                        printf("[ Console Server send: ]\n%s\n", request);
                }

                if (FD_ISSET(client_fd, &rwfd)) {
                    len = recv(client_fd, buf, MAXLENGTH, 0);

                    if ( (len > 0) && (strncmp(buf, "quit", 4) == 0)) {
                        printf("Client request close connect.\n");
                        close(client_fd);
                        break;
                    } else {
                        printf("[Client send: ]\n%s\n", buf);
                        //if (!responsed) {
                        if (1) {
                            //responsed = 1;
                            if (responsed == 0) {
                                responsed = 1;
                                parsestr(request, buf);
                            }
                            if (send(client_fd, request, MAXLENGTH, 0) > 0) {
                                printf("[Server send: ]\n%s\n", request);
                            }

                        }
                    }
                } /* if (FD_ISSET(client_fd, &rwfd)) */
            }

        } // while (1)
    }

    return 0;
}

服务器日志:

vincent@Vincent:/mnt/share/websocket$ ./a.out 
127.0.0.1 connected.
[Client send: ]
GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: localhost:49880
Origin: null
Pragma: no-cache
Cache-Control: no-cache
Sec-WebSocket-Key: XZaYANDATZBlVK9B3zIcOA==
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: x-webkit-deflate-frame
User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.14 Safari/537.36

[Server send: ]
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: DkeUbVTGuGuFSRO7YXwHyWZNsgc=


[Client send: ]
GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: localhost:49880
Origin: null
Pragma: no-cache
Cache-Control: no-cache
Sec-WebSocket-Key: XZaYANDATZBlVK9B3zIcOA==
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: x-webkit-deflate-frame
User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.14 Safari/537.36


[Server send: ]
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: DkeUbVTGuGuFSRO7YXwHyWZNsgc=


[Client send: ]
GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: localhost:49880
Origin: null
Pragma: no-cache
Cache-Control: no-cache
Sec-WebSocket-Key: XZaYANDATZBlVK9B3zIcOA==
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: x-webkit-deflate-frame
User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.14 Safari/537.36


[Signal Received: 13]

我检查了 websocket 协议,似乎响应格式是正确的。有人知道服务器出了什么问题吗?提前致谢!

4

0 回答 0