Search code examples
windowswinapiwinsock

winsock time loop send message does not work


Using winsock, I got a client and a server, when connect is done and i send a message the first time i can recv it in the server but after that when I do a time loop i can not show them on the screen. the send message inside the time loop does not return an error. I know this is a weird problem but if you take a look at timerCb that's where the send function is, it does not return an error but in my server i cannot print it. I have also tried making a new while loop with a parameter of recv it still did not work.

This is my client,

char receivingMessage[1000];
char messageInitiation[90] = "Hello YUMATKARA, conn pls bro hhhasf7sasflljh89";
VOID CALLBACK timerCb(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
//main
  SetTimer(NULL, 0, 3600, timerCb);

  if(WSAStartup(MAKEWORD(2, 2), &ws) != 0){
    printf("WSA err %d \n", GetLastError());
  }else{
  }

  if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET){
    printf("Invalid Socket \n");
  }else{
    printf("socket binded \n");
  }

  rmtServer.sin_addr.s_addr = inet_addr("127.0.0.1");
  rmtServer.sin_port = htons(4743);
  rmtServer.sin_family = AF_INET;

  if((connect(s, (struct sockaddr*)&rmtServer, sizeof(struct sockaddr_in))) != 0){
    printf("\n err %d", GetLastError());
  }else{
    printf("\n connected");
    send(s, messageInitiation, strlen(messageInitiation), 0);
    recv(s, receivingMessage, 1000, 0);
    printf("\n %s", receivingMessage);
    int liop;
    liop = strcmp(receivingMessage, "I got you!!");
    if(liop == 0){
      connectedYet = TRUE;
    }
    printf("\n is it true: ? %d\n", connectedYet);
  }

  while(GetMessage(&message, NULL, 0, 0) > 0){
    TranslateMessage(&message);
    DispatchMessage(&message);
  }

//outside main

VOID CALLBACK timerCb(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime){
  char *msgg = "Hello YUMATKARA, conn pls bro hhhasf7sasflljh89";
  printf("\n%s\n", "timing");
  if(send(s, msgg, strlen(msgg), 0) == SOCKET_ERROR){
    printf("err :%d\n", GetLastError());
  }
}

And this is my server

#include <windows.h>
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdParam, int iCmdShow) {
  MSG message;
  WSADATA ws;
  SOCKET s, incomingSocket;
  struct sockaddr_in server, client;
  char incomingMessage[1800];
  int recvState;
  WSAStartup(MAKEWORD(2, 2), &ws);

  s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

  server.sin_port = htons(4743);
  server.sin_addr.s_addr = inet_addr("127.0.0.1");
  server.sin_family = AF_INET;

  bind(s, (struct sockaddr *)&server, sizeof(server));

  listen(s, 1300);

  int g = sizeof(struct sockaddr_in);

  while((incomingSocket = accept(s, (struct sockaddr *)&client, &g)) != INVALID_SOCKET){
      printf("%s\n", inet_ntoa(client.sin_addr));
      printf("conn\n");
      if((recvState = recv(incomingSocket, incomingMessage, 2500, 0)) == SOCKET_ERROR){
      }else{
        int as;
        if((as = strcmp(incomingMessage, "Hello YUMATKARA, conn pls bro hhhasf7sasflljh89")) == 0){
          printf("\n identical");
          send(incomingSocket, "I got you!!", 11, 0);
        }
        printf("\n :%s\n", incomingMessage);
      }
  }

  if(incomingSocket == INVALID_SOCKET){
    printf("invalid socket");
  }

  return 0;
}

UPDATE

I have added this in my server code, before return 0 it does not display anything at all.

  while((recvState = recv(incomingSocket, incomingMessage, 50, 0)) > 0) {
    printf("\n new msg %s\n", incomingMessage);
  }

Solution

  • TCP is a byte stream, not message-oriented like you are expecting.

    recv() is not guaranteed to return complete messages. It could return as little as 1 byte, or it could return partial bytes from a message, or even bytes from multiple messages. You have to handle buffering and message framing in your code logic. And pay attention to its return value so you know how much it actually read. If you are expecting more data than is read, you have to call recv() again to read the rest, potentially many times. So use a loop.

    So, either:

    1. Have the sender send a string's length as a fixed-length value before then sending the actual characters. Then have the receiver read the length to know how many characters to read.

    2. Have the sender send a unique terminator after each string, like a nul character or even a CRLF, then the receiver can keep reading until it encounters the terminator.

    As for send(), it is not guaranteed to send complete data, either. It could send as few as 1 byte, or at least less than what you requested. So you have to pay attention to its return value, too, to know how much it actually sent. If it doesn't send everything in one go, you have to call it again to send any remaining data, potentially many times. So use a loop.

    For example, try something more like this:

    Client:

    const char messageInitiation* = "Hello YUMATKARA, conn pls bro hhhasf7sasflljh89";
    
    char* readStr(SOCKET s)
    {
        char *str = NULL;
        char buffer[100], ch;
        int buf_len = 0, str_len = 0, ret;
    
        do
        {
            ret = recv(s, &ch, 1, 0);
            if (ret == SOCKET_ERROR)
            {
                printf("recv err %d\n", WSAGetLastError());
                return SOCKET_ERROR;
            }
    
            if (ch == '\0')
                break;
    
            if (buf_len == sizeof(buffer))
            {
                char *newstr = (char*) realloc(str, str_len + buf_len + 1);
                if (!newstr)
                {
                    printf("memory err\n");
                    free(str);
                    return NULL;
                }
    
                str = newstr;
    
                memcpy(str + str_len, buffer, buf_len);
                str_len += buf_len;
    
                buf_len = 0;
            }
    
            buffer[buf_len++] = ch;
        }
        while (true);
    
        if (buf_len > 0)
        {
            char *newstr = (char*) realloc(str, str_len + buf_len + 1);
            if (!newstr)
            {
                printf("memory err\n");
                free(str);
                return NULL;
            }
    
            str = newstr;
    
            memcpy(str, buffer, buf_len);
            str_len += buf_len;
        }
    
        str[str_len] = '\0';
    
        return str;
    }
    
    int sendStr(SOCKET s, const char *str)
    {
        const unsigned char *pstr = (const unsigned char*) str;
        int len = strlen(str) + 1, ret;
    
        do
        {
            ret = send(s, pstr, len, 0);
            if (ret == SOCKET_ERROR)
            {
                printf("send err %d\n", WSAGetLastError());
                return SOCKET_ERROR;
            }
            pstr += ret;
            len -= ret;
        }
        while (len > 0);
    
        return 0;
    }
    
    /* alternatively:
    
    int readAll(SOCKET s, void *data, int len)
    {
        unsigned char *pdata = (unsigned char *) data;
        int ret;
    
        while (len > 0)
        {
            ret = recv(s, pdata, len, 0);
            if (ret == SOCKET_ERROR)
            {
                printf("recv err %d\n", WSAGetLastError());
                return SOCKET_ERROR;
            }
            pdata += ret;
            len -= ret;
        }
    
        return 0;
    }
    
    int readStr(SOCKET s)
    {
        int32_t len = 0;
        if (readAll(s, &len, sizeof(len)) == SOCKET_ERROR)
            return NULL;
    
        char *str = (char*) malloc(len + 1);
        if (!str)
        {
            printf("memory err\n");
            return NULL;
        }
    
        if (readAll(s, str, len) == SOCKET_ERROR)
        {
            free(str);
            return NULL;
        }
    
        str[len] = '\0';
    
        return str;
    }
    
    int sendAll(SOCKET s, const void *data, int len)
    {
        const unsigned char *pdata = (const unsigned char*) data;
        int ret;
    
        while (len > 0)
        {
            ret = send(s, pdata, len, 0);
            if (ret == SOCKET_ERROR)
            {
                printf("send err %d\n", WSAGetLastError());
                return SOCKET_ERROR;
            }
            pdata += ret;
            len -= ret;
        }
    
        return 0;
    }
    
    int sendStr(SOCKET s, const char *str)
    {
        int32_t len = strlen(str) + 1;
        int ret = sendAll(s, &len, sizeof(len));
        if (ret == 0)
            ret = sendAll(s, str, len);
        return ret;
    }
    */
    
    VOID CALLBACK timerCb(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
    {
        printf("\n%s\n", "timing");
        if (!sendStr(s, messageInitiation))
            PostQuitMessage(0);
    }
    
    int main()
    {
        WSADATA ws;
        int ret = WSAStartup(MAKEWORD(2, 2), &ws);
        if (ret != 0)
        {
            printf("WSA err %d\n", ret);
            return -1;
        }
    
        SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (s == INVALID_SOCKET)
        {
            printf("socket err %d\n", WSAGetLastError());
            WSACleanup();
            return -1;
        }
    
        printf("socket created\n");
    
        struct sockaddr_in rmtServer = {};
        rmtServer.sin_family = AF_INET;
        rmtServer.sin_addr.s_addr = inet_addr("127.0.0.1");
        rmtServer.sin_port = htons(4743);
    
        if (connect(s, (struct sockaddr*)&rmtServer, sizeof(struct sockaddr_in)) == SOCKET_ERROR)
        {
            printf("connect err %d\n", WSAGetLastError());
            closesocket(s);
            WSACleanup();
            return -1;
        }
    
        printf("connected\n");
    
        if (sendStr(s, messageInitiation) != 0)
        {
            closesocket(s);
            WSACleanup();
            return -1;
        }
    
        char *receivingMessage = recvStr(s);
        if (!receivingMessage)
        {
            closesocket(s);
            WSACleanup();
            return -1;
        }
    
        printf("%s\n", receivingMessage);
        BOOL connectedYet = (strcmp(receivingMessage, "I got you!!") == 0);
        printf("is it true: ? %d\n", connectedYet);
        free(receivingMessage);
    
        SetTimer(NULL, 0, 3600, timerCb);
    
        MSG message;
        while (GetMessage(&message, NULL, 0, 0) > 0)
        {
            TranslateMessage(&message);
            DispatchMessage(&message);
        }
    
        closesocket(s);
        WSACleanup();
    
        return 0;
    }
    

    Server:

    #include <windows.h>
    #include <winsock2.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    // see client code above
    char* readStr(SOCKET s);
    int sendStr(SOCKET s, const char *str);
    
    int main()
    {
        struct sockaddr_in server = {0}, client;
    
        WSADATA ws;
        int ret = WSAStartup(MAKEWORD(2, 2), &ws);
        if (ret != 0)
        {
            printf("WSA err %d\n", ret);
            return -1;
        }
    
        SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (s == INVALID_SOCKET)
        {
            printf("socket err %d\n", WSAGetLasatError());
            WSACleanup();
            return -1;
        }
    
        struct sockaddr_in server = {};
        server.sin_family = AF_INET;
        server.sin_addr.s_addr = inet_addr("127.0.0.1");
        server.sin_port = htons(4743);
    
        ret = bind(s, (struct sockaddr *)&server, sizeof(server));
        if (ret == SOCKET_ERROR)
        {
            printf("bind err %d\n", WSAGetLastError());
            closesocket(s);
            WSACleanup();
            return -1;
        }
    
        if (listen(s, 10) == SOCKET_ERROR)
        {
            printf("listen err %d\n", WSAGetLastError());
            closesocket(s);
            WSACleanup();
            return -1;
        }
    
        int g, iResult;
        struct sockaddr_in client;
    
        do
        {
            g = sizeof(client);
    
            SOCKET incomingSocket = accept(s, (struct sockaddr *)&client, &g);
            if (incomingSocket == INVALID_SOCKET)
            {
                printf("accept err %d\n", WSAGetLastError());
                closesocket(s);
                WSACleanup();
                return -1;
            }
    
            printf("%s conn\n", inet_ntoa(client.sin_addr));
    
            char *incomingMessage = recvStr(incomingSocket);
            if (incomingMessage)
            {
                printf("%s\n", incomingMessage);
                if (incomingMessage, "Hello YUMATKARA, conn pls bro hhhasf7sasflljh89") == 0)
                {
                    printf("identical\n");
                    sendStr(incomingSocket, "I got you!!");
                }
            }
    
            closesocket(incomingSocket);
        }
        while (true);
    
        return 0;
    }