Skip to content

Instantly share code, notes, and snippets.

@SangSama
Created April 29, 2020 04:16
Show Gist options
  • Save SangSama/07b0d2c7a5f35b9c5dd54b991e4406b3 to your computer and use it in GitHub Desktop.
Save SangSama/07b0d2c7a5f35b9c5dd54b991e4406b3 to your computer and use it in GitHub Desktop.

Revisions

  1. SangSama created this gist Apr 29, 2020.
    190 changes: 190 additions & 0 deletions ChatServerWSAAsync
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,190 @@
    #include <stdio.h>

    #define _WINSOCK_DEPRECATED_NO_WARNINGS
    #include <winsock2.h>
    #pragma warning(disable:4996)
    #pragma comment(lib, "ws2_32")

    #define WM_SOCKET WM_USER + 1

    BOOL CALLBACK WinProc(HWND, UINT, WPARAM, LPARAM);
    void RemoveClient(CLIENT_INFO*, int*, int*);

    typedef struct {
    SOCKET client;
    BOOL isRegistered;
    char* id;
    } CLIENT_INFO;

    CLIENT_INFO clients[64];
    int numClients = 0;

    int main()
    {
    WSADATA wsa;
    WSAStartup(MAKEWORD(2, 2), &wsa);

    SOCKADDR_IN addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(9000);

    SOCKET listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    bind(listener, (SOCKADDR*)&addr, sizeof(addr));
    listen(listener, 5);

    WNDCLASS wndclass;
    const CHAR* providerClass = "AsyncSelect";
    HWND window;

    wndclass.style = 0;
    wndclass.lpfnWndProc = (WNDPROC)WinProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = NULL;
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = (LPCWSTR)providerClass;

    if (RegisterClass(&wndclass) == 0)
    return NULL;

    // Create a window
    if ((window = CreateWindow((LPCWSTR)providerClass, L"", WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
    NULL, NULL, NULL, NULL)) == NULL)
    return NULL;

    WSAAsyncSelect(listener, window, WM_SOCKET, FD_ACCEPT);

    MSG msg; // truyen nhan du lieu
    while (GetMessage(&msg, NULL, 0, 0) > 0)
    {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }

    }

    BOOL CALLBACK WinProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
    {
    int index;
    if (wMsg == WM_SOCKET)
    {
    // kiem tra loi
    if (WSAGETSELECTERROR(lParam))
    {
    closesocket(wParam);
    return TRUE;
    }

    // chap nhan ket noi
    if (WSAGETSELECTEVENT(lParam) == FD_ACCEPT)
    {
    SOCKET client = accept(wParam, NULL, NULL);
    printf("New client accepted: %d\n", client);

    CLIENT_INFO clientInfo;
    clientInfo.client = client;
    clientInfo.isRegistered = FALSE;
    clientInfo.id = NULL;

    clients[numClients] = clientInfo;
    numClients++;

    const char* helloMsg = "Dang nhap theo cu phap \"[client_id:] [your_id]\".\n";
    send(client, helloMsg, strlen(helloMsg), 0);

    WSAAsyncSelect(client, hWnd, WM_SOCKET, FD_READ | FD_CLOSE); // them 2 mat na READ, CLOSE
    // (soket client, cua so , ma thong diep, su kien) => CALLBACk lai duoc goi
    }

    // client dk giai phong ben tren nen se luwu vao wParam
    if (WSAGETSELECTEVENT(lParam) == FD_READ)
    {
    char buf[256];
    const char* errorMsg = "Sai cu phap. Hay nhap lai.\n";
    int ret;
    ret = recv(wParam, buf, sizeof(buf), 0);


    for (int i = 0; i < numClients; i++)
    {
    if (clients[i].client == wParam) {
    index = i;
    break;
    }
    }

    char cmd[16], id[32], tmp[32];

    buf[ret] = 0;
    printf("Received: %s\n", buf);


    if (!clients[index].isRegistered) {

    ret = sscanf(buf, "%s %s %s", cmd, id, tmp);

    // kiem tra cu phap
    if (ret == 2) {
    if (strcmp(cmd, "client_id:") == 0) {
    const char* okMsg = "Dang nhap thanh cong. Hay nhap thong diep de chuyen tiep.\n";
    send(wParam, okMsg, strlen(okMsg), 0);

    clients[index].id = id;
    clients[index].isRegistered = TRUE;
    }
    else {
    send(wParam, errorMsg, strlen(errorMsg), 0);
    }
    }else{
    send(wParam, errorMsg, strlen(errorMsg), 0);
    }
    }
    else {
    char sendBuf[256];
    ret = sscanf(buf, "%s", cmd);
    if (ret == -1 || cmd[0] != '@'){
    send(wParam, errorMsg, strlen(errorMsg), 0);
    }
    else {
    char* id = clients[index].id;
    sprintf(sendBuf, "%s: %s", id, buf + strlen(cmd) + 1);
    if (strcmp(cmd, "@all") == 0)
    {
    // Chuyen tiep tin nhan den cac client khac
    for (int i = 0; i < numClients; i++)
    if (clients[i].client != wParam)
    send(clients[i].client, sendBuf, strlen(sendBuf), 0);
    }
    else
    {
    for (int i = 0; i < numClients; i++)
    if (strcmp(clients[i].id, cmd + 1) == 0)
    send(clients[i].client, sendBuf, strlen(sendBuf), 0);
    }
    }

    }
    }

    if (WSAGETSELECTEVENT(lParam) == FD_CLOSE)
    {
    RemoveClient(clients, &numClients, &index);
    closesocket(wParam);
    }
    }
    }
    void RemoveClient(CLIENT_INFO* clients, int* numClients, int* i)
    {
    if (*i < *numClients - 1)
    clients[*i] = clients[*numClients - 1];
    free(clients[*i].id);
    *numClients = *numClients - 1;
    *i = *i - 1;
    }