Hyunsoo
Hyunsoo

Reputation: 139

Websocket implementation in C

I'm korean student. I'm writing web server program by written C. I'don't know why client(javascript) cannot receive data from server. client(browser) is also well connect to server. but client cannot receive data from server.

I have searched about my problem on google. but I could not find out the reason. the search output was all just relavant usage of library. please see my code if you have a time to see

#define _WINSOCK_DEPRECATED_NO_WARNINGS 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <process.h>
#include <sys/types.h>
#include <windows.h>
#include "dirent.h"


#define BUF_SIZE  2048
#define BUF_SMALL  100

unsigned  WINAPI RequestHandler(void* arg);
char* ContentType(char* file);
void SendData(SOCKET sock, char* ct, char* fileName);
void SendErrorMSG(SOCKET sock);
void ErrorHandling(char *message);
unsigned WINAPI updateFiles(void* arg);

typedef struct _clnt {
    SOCKET hClntSock;
    SOCKADDR_IN* clntAdr;
}Clnt, *LPClnt;

enum FLAG { SEND_TO_WEB, SEND_TO_CLIENT };

SOCKET hServSock;
SOCKADDR_IN servAdr;
int flag;


int main(int argc, char *argv[])
{
    WSADATA wsaData;
    SOCKET hClntSock;
    SOCKADDR_IN* clntAdr;
    LPClnt clnt;

    HANDLE hThread;
    DWORD dwThreadID;
    int clntAdrSize;

    if (argc != 2) {
        printf("Usage : %s <port>\n", argv[0]);
        exit(1);
    }

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
        ErrorHandling("WSAStartup() error!");

    hServSock = socket(PF_INET, SOCK_STREAM, 0);
    memset(&servAdr, 0, sizeof(servAdr));
    servAdr.sin_family = AF_INET;
    servAdr.sin_addr.s_addr = htonl(INADDR_ANY);
    servAdr.sin_port = htons(atoi(argv[1]));

    if (bind(hServSock, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR)
        ErrorHandling("bind() error");
    if (listen(hServSock, 5) == SOCKET_ERROR)
        ErrorHandling("listen() error");


    /* 요청 및 응답 */
    while (1)
    {       
        clnt = (LPClnt)malloc(sizeof(Clnt));
        clntAdr = (SOCKADDR_IN*)malloc(sizeof(SOCKADDR_IN));
        clntAdrSize = sizeof(*clntAdr);
        hClntSock = accept(hServSock, (SOCKADDR*)clntAdr, &clntAdrSize);

        clnt->clntAdr = clntAdr;
        clnt->hClntSock = hClntSock;

        printf("Connection Request : %s:%d\n",
            inet_ntoa(clntAdr->sin_addr), ntohs(clntAdr->sin_port));
        printf("Socket Number : %d\n", clnt->hClntSock);

        hThread = (HANDLE)_beginthreadex(
            NULL, 0, RequestHandler, (void*)clnt, 0, (unsigned *)&dwThreadID);
    }
    closesocket(hServSock);
    WSACleanup();
    return 0;
}

unsigned WINAPI RequestHandler(void *arg)
{
    SOCKET hClntSock = ((LPClnt)arg)->hClntSock;
    SOCKADDR_IN* clntAdr = ((LPClnt)arg)->clntAdr;
    char buf[BUF_SIZE];
    char method[BUF_SMALL];
    char ct[BUF_SMALL];
    char fileName[BUF_SMALL];
    char* context;


    recv(hClntSock, buf, BUF_SIZE, 0);


    if (strstr(buf, "HTTP/") == NULL)    // HTTP에 의한 요청인지 확인
    {
        SendErrorMSG(hClntSock);
        closesocket(hClntSock);
        return 1;
    }
    else if (strstr(buf, "websocket")) {
        printf("WebSocket is connected\n");
        _beginthreadex(NULL, 0, updateFiles, (void*)hClntSock, 0, NULL);
        return 1;
    }

    strcpy_s(method, sizeof(method), strtok_s(buf, " /", &context));
    if (strcmp(method, "GET"))    // GET 방식 요청인지 확인 
        SendErrorMSG(hClntSock);

    strcpy_s(fileName, sizeof(fileName), strtok_s(NULL, " /", &context));    // 요청 파일이름 확인
    if(!strcmp(fileName, "HTTP"))  // index.html을 명시하지않앗다면
        strcpy_s(fileName, sizeof(fileName), "index.html");

    strcpy_s(ct, sizeof(ct), ContentType(fileName));    // Content-type 확인  
    SendData(hClntSock, ct, fileName);    // 응  답
    return 0;
}

void SendData(SOCKET sock, char* ct, char* fileName)
{
    char protocol[] = "HTTP/1.0 200 OK\r\n";
    char servName[] = "Server:simple web server\r\n";
    char cntLen[] = "Content-length:2048\r\n";
    char cntType[BUF_SMALL];
    char buf[BUF_SIZE];
    FILE* sendFile;

    sprintf_s(cntType, sizeof(cntType), "Content-type:%s; charset=UTF-8\r\n\r\n", ct);
    if (fopen_s(&sendFile, fileName, "r") != 0)
    {
        SendErrorMSG(sock);
        return;
    }

    /* 헤더 정보 전송 */
    send(sock, protocol, strlen(protocol), 0);
    send(sock, servName, strlen(servName), 0);
    send(sock, cntLen, strlen(cntLen), 0);
    send(sock, cntType, strlen(cntType), 0);

    /* 요청 데이터 전송 */
    while (fgets(buf, BUF_SIZE, sendFile) != NULL) {
        send(sock, buf, strlen(buf), 0);
    }

    closesocket(sock);   // HTTP 프로토콜에 의해서 응답 후 종료
}

void SendErrorMSG(SOCKET sock)   // 오류 발생시 메시지 전달
{
    char protocol[] = "HTTP/1.0 400 Bad Request\r\n";
    char servName[] = "Server:simple web server\r\n";
    char cntLen[] = "Content-length:2048\r\n";
    char cntType[] = "Content-type:text/html\r\n\r\n";
    char content[] = "<html><head><title>NETWORK</title></head>"
        "<body><p>오류 발생! 요청 파일명 및 요청 방식 확인!"
        "</p></body></html>";

    send(sock, protocol, strlen(protocol), 0);
    send(sock, servName, strlen(servName), 0);
    send(sock, cntLen, strlen(cntLen), 0);
    send(sock, cntType, strlen(cntType), 0);
    send(sock, content, strlen(content), 0);
    closesocket(sock);
}

char* ContentType(char* file)    // Content-Type 구분
{
    char extension[BUF_SMALL];
    char fileName[BUF_SMALL];
    char* context;

    strcpy_s(fileName, sizeof(fileName), file);
    strtok_s(fileName, ".", &context);
    strcpy_s(extension, sizeof(extension), strtok_s(NULL, ".", &context));
    if (!strcmp(extension, "html") || !strcmp(extension, "htm"))
        return "text/html";
    else
        return "text/plain";
}

unsigned WINAPI updateFiles(void* arg) {
    struct dirent* file;
    char* str;
    SOCKET webSock = (SOCKET)arg;
    DIR* dir;

    while (1) {
        dir = opendir(".");
        printf("to sent %d\n", webSock);
        while (file = readdir(dir)) {
            //printf("%s\n", file->d_name);
            send(webSock, 1, 1, 0);
        }
        Sleep(1000);
    }
}

void ErrorHandling(char* message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

<html>
<head>
    <meta charset="UTF-8">
    <title>NETWORK</title>
</head>
    <body>
        <ul id="list">
            <li>
                first11
            </li>
            <li>
                second
            </li>
        </ul>
    </body>

<script>
    const list = document.querySelector("#list");
    const sock = new WebSocket('ws://127.0.0.1:80');
    const arr = [];
    let li;

    sock.onmessage = evt => {
        console.log("ASD")
        li = document.createElement("li");
        if (arr.indexOf(evt.data) == -1) {
            arr.push(evt.data);
            li.innerHTML = evt.data;
            list.appendChild(li);
        }
    }
    
</script>
</html>

this is my output. if my program don't has problem, browser has to output "ASD", but there is nothing.

enter image description here

enter image description here

Upvotes: 0

Views: 4619

Answers (1)

Myst
Myst

Reputation: 19221

WebSockets is the name of a protocol, it's not raw TCP/IP sockets.

Make sure you wrap the TCP/IP data in a WebSocket packet before sending the data to the TCP/IP connection.

Also, don't write HTTP data to the WebSocket after the HTTP protocol was "upgraded".

See the RFC for the WebSocket protocol for details.

Upvotes: 1

Related Questions