2016-04-21 151 views
0

我正在创建一个Winsock应用程序,并且在尝试执行关机功能时,服务器中的某些内容失败。该项目会建立并运行,但是当客户端的第一个连接到达时,它会占用它并且在命令行中显示失败: “shutdown failed:10038”。 我一直在阅读有关错误,据说它通常是因为函数关闭被应用于不是SOCKET的东西或类似的东西。但是在调试时我看到它显然是一个Socket,所以我不知道该怎么做。关机失败,出现错误10038

#undef UNICODE 

#define WIN32_LEAN_AND_MEAN 

#include "stdafx.h" 

// Need to link with Ws2_32.lib 
#pragma comment (lib, "Ws2_32.lib") 
// #pragma comment (lib, "Mswsock.lib") 

#define DEFAULT_BUFLEN 512 
#define DEFAULT_PORT "27015" 
//Function declaration 
const std::string currentDateTime(); 
int __cdecl NewClient(SOCKET ListenSocket, SOCKET ClientSocket, char *recvbuf, int recvbuflen, int iSendResult, int iResult); 
std::string CommandGet(char *recvbuf); 
void Login(char *recvbuf); 
void print_data(char *recvbuf); 
string GetUsername(char *recvbuf); 
string GetThirdToken(char *recvbuf); 

//Map & Struct creation 
struct message{ 
    static unsigned int last_id; 
    unsigned int id; 
    std::string baa; 
    std::string timestamp; 
    message(){}; 
    message(const std::string& recvbuf_baa,const std::string& a_timestamp) : 
    baa(recvbuf_baa), timestamp(a_timestamp), id(++last_id) 
    { 
    } 
}; 
map<std::string,std::vector<message *> > data; 
map<std::string,std::vector<string> > followers; 
//Global variables 
unsigned int message::last_id = 0; 
map<std::string,bool> loggedin; 

int __cdecl main(void) 
{ 
    WSADATA wsaData; 
    int iResult; 

    SOCKET ListenSocket = INVALID_SOCKET; 
    SOCKET ClientSocket = INVALID_SOCKET; 

    struct addrinfo *result = NULL; 
    struct addrinfo hints; 



    int iSendResult=0; 
    char recvbuf[DEFAULT_BUFLEN]; 
    int recvbuflen = DEFAULT_BUFLEN; 

    // Initialize Winsock 
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData); 
    if (iResult != 0) { 
     printf("WSAStartup failed with error: %d\n", iResult); 
     return 1; 
    } 

    ZeroMemory(&hints, sizeof(hints)); 
    hints.ai_family = AF_INET; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_protocol = IPPROTO_TCP; 
    hints.ai_flags = AI_PASSIVE; 
    while(true){ 
     // Resolve the server address and port 
     iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result); 
     if (iResult != 0) { 
      printf("getaddrinfo failed with error: %d\n", iResult); 
      WSACleanup(); 
      return 1; 
     } 

     // Create a SOCKET for connecting to server 
     ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); 
     if (ListenSocket == INVALID_SOCKET) { 
      printf("socket failed with error: %ld\n", WSAGetLastError()); 
      freeaddrinfo(result); 
      WSACleanup(); 
      return 1; 
     } 

     // Setup the TCP listening socket 
     iResult = ::bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen); 
     if (iResult == SOCKET_ERROR) { 
      printf("bind failed with error: %d\n", WSAGetLastError()); 
      freeaddrinfo(result); 
      closesocket(ListenSocket); 
      WSACleanup(); 
      return 1; 
     } 

     freeaddrinfo(result); 

     iResult = listen(ListenSocket, SOMAXCONN); 
     if (iResult == SOCKET_ERROR) { 
      printf("listen failed with error: %d\n", WSAGetLastError()); 
      closesocket(ListenSocket); 
      WSACleanup(); 
      return 1; 
     } 
     // Accept a client socket 
     ClientSocket = accept(ListenSocket, NULL, NULL); 
     if (ClientSocket == INVALID_SOCKET) { 
      printf("accept failed with error: %d\n", WSAGetLastError()); 
      closesocket(ListenSocket); 
      WSACleanup(); 
      return 1; 
     } 

     // No longer need server socket 
     closesocket(ListenSocket); 

     return NewClient(ListenSocket, ClientSocket, recvbuf, recvbuflen, iSendResult, iResult); 



    } 
} 

int __cdecl NewClient(SOCKET ListenSocket, SOCKET ClientSocket, char *recvbuf, int recvbuflen, int iSendResult, int iResult){ 



     // Receive until the peer shuts down the connection 
     do { 
      iResult = recv(ClientSocket, recvbuf, recvbuflen, 0); 
      if (iResult > 0) { 
       printf("Bytes received: %d\n", iResult); 
       std::string cmd=CommandGet(recvbuf); 
       if (cmd=="log"){ 
        std::string usrn=GetUsername(recvbuf); 
        std::string recvbuf_str=""; 
        for(auto it=loggedin.begin();it!=loggedin.end();it++){ 
         if ((*it).first==usrn){ 
          recvbuf_str="loggedin"; 
          if ((*it).second){ 
           recvbuf_str="cantlogin"; 
           break; 
          } 
          else{ 
           loggedin[usrn]=1; 
           break; 
          } 
          break; 
         } 
        } 
        if (recvbuf_str==""){ 
         recvbuf_str="newlogin"; 
         Login(recvbuf); 
        } 
        iSendResult = send(ClientSocket, recvbuf_str.c_str(), iResult, 0); 
        if (iSendResult == SOCKET_ERROR) { 
         printf("send failed with error: %d\n", WSAGetLastError()); 
         closesocket(ClientSocket); 
         WSACleanup(); 
          return 1; 
        } 
       } 


      } 

      else if (iResult == 0){ 
       printf("Connection closing...\n"); 
       closesocket(ClientSocket);} 
      else { 
       printf("recv failed with error: %d\n", WSAGetLastError()); 
       closesocket(ClientSocket); 
       WSACleanup(); 
        return 1; 
      } 

     } while (iResult > 0); 


    // shutdown the connection since we're done 
    iResult = shutdown(ClientSocket, SD_SEND); 
    if (iResult == SOCKET_ERROR) { 
     printf("shutdown failed with error: %d\n", WSAGetLastError()); 
     closesocket(ClientSocket); 
     WSACleanup(); 
     return 1; 
    } 

    // cleanup 
    closesocket(ClientSocket); 
    WSACleanup(); 

    return 0; 
} 
const std::string currentDateTime() { 
    time_t  now = time(0); 
    struct tm tstruct; 
    char  buf[80]; 
    localtime_s(&tstruct, &now); 
    strftime(buf, sizeof(buf), "%Y-%m-%d %X", &tstruct); 
    return buf; 
} 

void Login(char *recvbuf){ 
    std::string usrn= GetUsername(recvbuf); 
    std::vector<message *> messages; 
    data[usrn]=messages; 
    std::vector<string> follow; 
    followers[usrn]=follow; 
    loggedin[usrn]=1; 
} 


void print_data(char *recvbuf){ 
    std::string usrn= GetUsername(recvbuf); 

    for(auto mapIt = data.cbegin(); mapIt != data.cend(); ++mapIt) 
    { 
    std::cout << "printing data for " << mapIt->first << ":" << std::endl; 
    for(auto vectIter = mapIt->second.cbegin(); vectIter != mapIt->second.cend(); ++vectIter) 
     { 
      std::cout << (*vectIter)->baa << ", " << (*vectIter)->timestamp << ", " 
        << (*vectIter)->id << std::endl; 
     } 
    } 
} 

void print_followers(char *recvbuf){ 
    std::string usrn= GetUsername(recvbuf); 

    for(auto mapIt = followers.cbegin(); mapIt != followers.cend(); ++mapIt) 
    { 
    std::cout << "printing followers for " << mapIt->first << ":" << std::endl; 
    for(auto vectIter = mapIt->second.cbegin(); vectIter != mapIt->second.cend(); ++vectIter) 
     { 
      std::cout << (*vectIter) << endl; 
     } 
    } 
} 

std::string CommandGet(char *recvbuf){ 
     int start0=0; 
     std::string recvbuf_cmd; 
     std::string recvstr(recvbuf); 
     start0=recvstr.find(';'); 
     recvbuf_cmd=recvstr.substr(0,start0); 
     return recvbuf_cmd; 
} 

string GetUsername(char *recvbuf){ 
    int start0=0, start1=0; 
    std::string recvbuf_usrn; 
    std::string recvstr(recvbuf); 
    start0=recvstr.find(';'); 
    start1=recvstr.find(';',start0+1); 
    recvbuf_usrn=recvstr.substr(start0+1,start1-start0-1); 
    return recvbuf_usrn; 
} 

string GetThirdToken(char *recvbuf){ 
    int start0=0, start1=0, start2=0; 
    std::string recvbuf_thirdtoken; 
    std::string recvstr(recvbuf); 
    start0=recvstr.find(';'); 
    start1=recvstr.find(';',start0+1); 
    start2=recvstr.find(';',start1+1); 
    recvbuf_thirdtoken=recvstr.substr(start1+1,start2-start1-1); 
    return recvbuf_thirdtoken; 
} 

我上传整个项目的情况下,你要检查它更深(https://mega.nz/#!dtcx1DCL!dKWV2ryDDfiXv5H3Mi2p4PrBpie2CGrGJOTAwvQAV8M),但问题是位于服务器(我简化了代码),客户端只是这样你就可以开始连接如输入用户名(但不关心它)。

在此先感谢您,任何帮助将不胜感激。

+0

不要给我们“整个项目”,特别是作为一个可以过时的链接,使整个问题变得毫无价值。相反,尝试创建一个[最小,完整和可验证的示例](http://stackoverflow.com/help/mcve)向我们展示,*在问题主体*中。如果你在做这件事时遇到了麻烦,那么从实际的代码中提取相关的部分,并在问题的主体中向我们显示*也*。如果你还没有这样做,请[阅读关于如何提出好问题](http://stackoverflow.com/help/how-to-ask)。 –

+0

@JoachimPileborg谢谢你的回答,我编辑了问题,直接在问题中提供服务器代码。 – 19mike95

回答

2

让我们考虑下面的行,从你所示源:

iResult = recv(ClientSocket, recvbuf, recvbuflen, 0); 
... 
else if (iResult == 0){ 
    printf("Connection closing...\n"); 
    closesocket(ClientSocket);} 
... 
iResult = shutdown(ClientSocket, SD_SEND); 

recv返回零,这意味着该连接已经关闭(很好)由另一端。发生这种情况时,请致电closesocket关闭插座。 但是然后你继续在封闭的socket上无条件地调用shutdown,导致你得到的错误。

简单的解决方案?只需关闭插座使用closesocket一次,无需shutdown在这里,我可以看到(很少有)。

+0

感谢您的回答,我试过这个,但是如果我这样做,服务器在第一次连接完成时关闭,并且我希望它仍然在监听下一个命令,我该怎么办? – 19mike95

+0

@ 19mike95这是一个完全不同的问题,并解决你应该仔细看看'main'函数中的逻辑。如果你不能手动执行你自己的代码,那么我建议你在调试器中逐行执行。如果你不知道如何解决这个问题,那么这是另一个问题的主题。 –

相关问题