winsock时间循环发送消息不起作用

时间:2017-10-03 23:33:11

标签: windows winapi winsock

使用winsock,我有一个客户端和一个服务器,当connect完成后我第一次发送消息我可以在服务器中恢复它但在那之后当我做一个时间循环时我无法显示他们在屏幕上。时间循环内的发送消息不会返回错误。我知道这是一个奇怪的问题,但如果你看一下发送功能所在的timerCb,它不会返回错误,但在我的服务器中我无法打印它。我还尝试使用recv参数创建一个新的while循环,但它仍无效。

这是我的客户,

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());
  }
}

这是我的服务器

#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;
}

更新

我已将此添加到我的服务器代码中,在return 0之前它根本不显示任何内容。

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

1 个答案:

答案 0 :(得分:1)

TCP是一个字节流,不像您期望的那样面向消息。

recv()无法保证返回完整的消息。它可以返回1个字节,或者它可以从消息返回部分字节,甚至从多个消息返回字节。您必须在代码逻辑中处理缓冲和消息框架。并注意其返回值,以便您知道它实际读取了多少。如果您期望的数据多于读取的数据,则必须再次调用recv()以阅读其余数据,可能需要多次。所以使用循环。

所以,要么:

  1. 让发送方将字符串的长度作为固定长度值发送,然后再发送实际字符。然后让接收器读取长度以了解要读取的字符数。

  2. 让发送方在每个字符串后发送一个唯一的终结符,如nul字符甚至是CRLF,然后接收方可以继续读取,直到它遇到终结符。

  3. 对于send(),也不保证发送完整数据。它可以发送少至1个字节,或至少少于您请求的内容。所以你必须注意它的返回值,才能知道它实际发送了多少。如果它不是一次性发送所有内容,则必须再次调用它以发送任何剩余数据,可能多次。所以使用循环。

    例如,尝试更像这样的事情:

    客户端:

    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;
    }
    

    服务器:

    #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;
    }