嘿,那里的社区很棒!
我回来了关于我用winsock制作的控制台服务器应用程序的问题。终于到了一个需要添加GUI的阶段,为此,我需要使用Windows子系统。
因此,我开始了迁移。
但是我在应用程序中的某个地方遇到了堆栈溢出问题,对于我一生来说,我不知道该在哪里。也许这与WIN是一个非阻塞子系统有关(希望我正确使用了vocab)。

无论如何,我希望邀请大家成为帮助者。非常感谢 :)

    #undef UNICODE

    #define WIN32_LEAN_AND_MEAN

    #include <windows.h>
    #include <winsock2.h>
    #include <ws2tcpip.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <iostream>
    #include <string>
    #include <conio.h>

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

int minitialize();
int msend(char msendbuf[512]);
char* mrecv(bool show);
int mshutdown();
void GoToXY(int column, int line);
int scroll(void);
int printm(char *inp);
int printm(char *inp, DWORD color);
int mexit();
char *vir = "true";

int clientnumber=0;
int currentclient=0;
int lastclient=0;

#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "10150"

struct _client
{
    bool con;
    sockaddr_in addr;   //Client info like ip address
    SOCKET cs;      //Client socket
    fd_set set;         //used to check if there is data in the socket
    std::string ip;
    std::string name;
    int i;              //any piece of additional info
} client[100];

WSADATA wsaData;
int iResult;


SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;

struct addrinfo *result = NULL;
struct addrinfo hints;

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

DWORD WINAPI recvfunc(LPVOID randparam)
{
    while (true) {
        ClientSocket=client[currentclient].cs;
        if (mrecv(true)=="1") {
            client[currentclient].con=false;
            ClientSocket=client[lastclient].cs;
            break;
        }
    }
    return 0;
}

DWORD WINAPI headerfunc(LPVOID randparam)
{
    Sleep(500);
    while (true) {
        CONSOLE_SCREEN_BUFFER_INFO SBInfo;
        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        GetConsoleScreenBufferInfo(hOut, &SBInfo);
        int xx = SBInfo.dwCursorPosition.X;
        int yy = SBInfo.dwCursorPosition.Y;
        GoToXY(0,0);
        HANDLE hHeaderColor;
        hHeaderColor = GetStdHandle(STD_OUTPUT_HANDLE);
        SetConsoleTextAttribute(hHeaderColor, FOREGROUND_GREEN);
        std::cout<<"Server Started.  Current Client:"<<currentclient<<"  Clients connected: "<<clientnumber<<"        ("<<xx<<","<<yy<<")   "<<lastclient;
        SetConsoleTextAttribute(hHeaderColor, 0 |
                                FOREGROUND_RED |
                                FOREGROUND_GREEN |
                                FOREGROUND_BLUE);
        GoToXY(xx,yy);
        Sleep(2000);
    }
    return 0;
}

DWORD WINAPI sendfunc(LPVOID randparam)
{
    while (true) {
        char mmessage[512];
        std::cin.getline(mmessage, 512);
        if (strlen(mmessage)<2) {
            GoToXY(0,23);
            sendfunc("1");
        }
        char msendbuf[512]="Server> ";
        strcat(msendbuf,mmessage);
        if (msend(msendbuf)==1) {
            "Client must have disconnected. Please select a new client.";
            sendfunc("1");
        }
        if ((strncmp(msendbuf,"Server> /",9)) != 0) {
            printm(msendbuf,FOREGROUND_INTENSITY);
        }
        GoToXY(0,23);
        for (int sp=0; sp<72; sp++) {
            std::cout<<" ";
        }
        GoToXY(0,23);
    }

    return 0;
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    minitialize();
    HANDLE hRecvThread;
    HANDLE hSendThread;
    HANDLE hHeaderThread;
    DWORD dwRecvThreadId;
    DWORD dwSendThreadId;
    DWORD dwHeaderThreadId;
    hHeaderThread = CreateThread(NULL,0,headerfunc,"1",0,&dwHeaderThreadId);
    for (int mf=2; mf<25; mf++) {
        std::cout<<"\n";
    }
    hSendThread = CreateThread(NULL,0,sendfunc,"1",0,&dwSendThreadId);

    // Accept a client socket
    for (int sock=1; sock<100; sock++) {
        ClientSocket = accept(ListenSocket, NULL, NULL);
        char sockprint[80];
        char sockchar[4];
        itoa(sock,sockchar,10);
        strcpy(sockprint,"Client ");
        strcat(sockprint,sockchar);
        strcat(sockprint," connected.");
        printm(sockprint);
        GoToXY(0,23);
        if (ClientSocket == INVALID_SOCKET) {
            printm("accept failed with error: %d\n", WSAGetLastError());
            closesocket(ListenSocket);
            WSACleanup();
            return 1;
        }
        client[sock].cs=ClientSocket;
        client[sock].con=true;
        lastclient=clientnumber;
        clientnumber++;
        currentclient=clientnumber;
        hRecvThread = CreateThread(NULL,0,recvfunc,"1",0,&dwRecvThreadId);
    }


    // shutdown the connection since we're done
    mshutdown();
    std::cin.ignore();

    return 0;
}

int printm(char *inp, DWORD color) {
    HANDLE hOut;

    hOut = GetStdHandle(STD_OUTPUT_HANDLE);

    SetConsoleTextAttribute(hOut,
                            color);
    printm(inp);
    SetConsoleTextAttribute(hOut, 0 |
                            FOREGROUND_RED |
                            FOREGROUND_GREEN |
                            FOREGROUND_BLUE);
    return 0;
}

int printm(char *inp) {
    CONSOLE_SCREEN_BUFFER_INFO SBInfo;
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    GetConsoleScreenBufferInfo(hOut, &SBInfo);
    int xx = SBInfo.dwCursorPosition.X;
    int yy = SBInfo.dwCursorPosition.Y;
    GoToXY(0,22);
    std::cout<<inp<<"\n";
    scroll();
    GoToXY(xx,yy);
    return 1;
}

int msend(char msendbuf[512])   // Send a message
{
    if (strncmp(msendbuf,"Server> /exit",(strlen(msendbuf))) == 0) {
        mexit();
    }
    if (strncmp(msendbuf,"Server> /set_client",19) == 0) {
        int nm=atoi(&msendbuf[20]);
        currentclient=nm;
        ClientSocket=client[nm].cs;
        char sockchar[4];
        itoa(ClientSocket,sockchar,10);
        char sockprint[80];
        strcpy(sockprint,"New Socket: ");
        strcat(sockprint,sockchar);
        printm(sockprint);
        char clientprint[80];
        strcpy(clientprint,"Client: ");
        strcat(clientprint,&msendbuf[20]);
        printm(clientprint);
    }
    if (strncmp(msendbuf,"Server> /list_clients",(strlen(msendbuf))) == 0) {
        printm("Clients:",FOREGROUND_RED);
        for (int cm=1; cm < 100; cm++) {
            int cn=client[cm].cs;
            if (cn>0) {
                char cli[80];
                char cmchar[4];
                char cnchar[80];
                itoa(cn,cnchar,10);
                itoa(cm,cmchar,10);
                strcpy(cli,cmchar);
                strcat(cli,"  ");
                strcat(cli,cnchar);
                strcat(cli," ");
                strcat(cli,client[cm].ip.c_str());
                strcat(cli," ");
                strcat(cli,client[cm].name.c_str());
                printm(cli,FOREGROUND_RED);
            }
            else {
                break;
            }
        }
    }
    if (strncmp(msendbuf,"Server> /test",(strlen(msendbuf))) == 0) {
        char ipcon[500];
        *ipcon=(system("ipconfig"));
    }
    if (strncmp(msendbuf,"Server> /help",(strlen(msendbuf))) == 0) {
        printm("Type /help for help or:");
        printm("/set_client [client number]");
        printm("/list_clients");
    }
    int iResult3 = send( ClientSocket, msendbuf, 512, 0 );
    if (iResult3 == SOCKET_ERROR) {
        printm("send failed with error: %d\n", WSAGetLastError());
        return 1;
    }
}

char* mrecv(bool show) //Recieve a message
{
    int iResult2 = recv(ClientSocket, recvbuf, 512, 0);
    if (iResult2 > 0) {
        if ((strncmp(recvbuf,"/",1)) != 0) {
            printm(recvbuf);
        }
        if (strncmp(recvbuf,"/ip",3) == 0) {
            client[clientnumber].ip=&recvbuf[4];
            char prin[80];
            strcpy(prin,"client[clientnumber].ip: ");
            strcat(prin,client[clientnumber].ip.c_str());
            printm(prin,FOREGROUND_BLUE);
        }
        if (strncmp(recvbuf,"/name",5) == 0) {
            client[clientnumber].name=&recvbuf[6];
            char prin2[80];
            strcpy(prin2,"client[clientnumber].name: ");
            strcat(prin2,client[clientnumber].name.c_str());
            printm(prin2,FOREGROUND_GREEN | FOREGROUND_BLUE);
        }
        if (strncmp(recvbuf,"/alert",5) == 0) {
            char *message=&recvbuf[7];
            char prin2[80];
            strcpy(prin2,client[clientnumber].name.c_str());
            strcat(prin2,": ");
            strcat(prin2, message);
            printm(prin2,FOREGROUND_RED);
        }
        if (strncmp(recvbuf,"Client> /alert",14) == 0) {
            char *message=&recvbuf[15];
            char prin2[80];
            strcpy(prin2,client[clientnumber].name.c_str());
            strcat(prin2,": ");
            strcat(prin2, message);
            printm(prin2,FOREGROUND_RED);
        }
    }
    else if (iResult2 == 0) {
        printf("Connection closing...\n");
        closesocket(ClientSocket);
        WSACleanup();
        return "1";
    }
    else  {
        printm("recv failed with error: %d\n", WSAGetLastError());
        printm("Client must have disconnected. Please select a new client.");
        return "1";
    }
    return recvbuf;
}

int minitialize()   //initialize the winsock server
{
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != 0) {
        printm("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;

    // Resolve the server address and port
    iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
    if ( iResult != 0 ) {
        printm("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) {
        printm("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) {
        printm("bind failed with error: %d\n", WSAGetLastError());
        freeaddrinfo(result);
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    freeaddrinfo(result);

    iResult = listen(ListenSocket, SOMAXCONN);
    if (iResult == SOCKET_ERROR) {
        printm("listen failed with error: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    unsigned long b=1;
    ioctlsocket(ClientSocket,FIONBIO,&b);


}

int mshutdown()     //shutdown the server
{
    iResult = shutdown(ClientSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printm("shutdown failed with error: %d\n", WSAGetLastError());
        closesocket(ClientSocket);
        WSACleanup();
        return 1;
    }

    // cleanup
    closesocket(ClientSocket);
    WSACleanup();
    return 0;
}

void GoToXY(int column, int line)
{
    // Create a COORD structure and fill in its members.
    // This specifies the new position of the cursor that we will set.
    COORD coord;
    coord.X = column;
    coord.Y = line;

    // Obtain a handle to the console screen buffer.
    // (You're just using the standard console, so you can use STD_OUTPUT_HANDLE
    // in conjunction with the GetStdHandle() to retrieve the handle.)
    // Note that because it is a standard handle, we don't need to close it.
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

    // Finally, call the SetConsoleCursorPosition function.
    if (!SetConsoleCursorPosition(hConsole, coord))
    {
        // Uh-oh! The function call failed, so you need to handle the error.
        // You can call GetLastError() to get a more specific error code.
        // ...
        return;
    }
}

int scroll( void )
{
    HANDLE hStdout;
    CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
    SMALL_RECT srctScrollRect, srctClipRect;
    CHAR_INFO chiFill;
    COORD coordDest;

    hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

    if (hStdout == INVALID_HANDLE_VALUE)
    {
        printf("GetStdHandle failed with %d\n", GetLastError());
        return 1;
    }

    // Get the screen buffer size.

    if (!GetConsoleScreenBufferInfo(hStdout, &csbiInfo))
    {
        printf("GetConsoleScreenBufferInfo failed %d\n", GetLastError());
        return 1;
    }

    // The scrolling rectangle

    srctScrollRect.Top = 1;
    srctScrollRect.Bottom = 22;
    srctScrollRect.Left = 0;
    srctScrollRect.Right = csbiInfo.dwSize.X - 1;

    // The destination for the scroll rectangle is one row up.

    coordDest.X = 0;
    coordDest.Y = 0;

    // The clipping rectangle

    srctClipRect.Top = 2;
    srctClipRect.Bottom = 22;
    srctClipRect.Left = 0;
    srctClipRect.Right = csbiInfo.dwSize.X - 1;

    // Fill the bottom row with blanks.

    chiFill.Attributes = FOREGROUND_RED;
    chiFill.Char.AsciiChar = (char)' ';

    // Scroll up one line.

    if(!ScrollConsoleScreenBuffer(
                hStdout,         // screen buffer handle
                &srctScrollRect, // scrolling rectangle
                &srctClipRect,   // clipping rectangle
                coordDest,       // top left destination cell
                &chiFill))       // fill character and color
    {
        printf("ScrollConsoleScreenBuffer failed %d\n", GetLastError());
        return 1;
    }
    return 0;
}

int mexit()
{
    msend("/server_closed");
    mshutdown();
    exit(0);
}

最佳答案

原来是我的“sendfunc”线程中的递归调用使我绊倒了。
特别,

        if (msend(msendbuf)==1) {
            "Client must have disconnected. Please select a new client.";
            sendfunc("1");
        }

因为我继续从自身调用“sendfunc”,所以导致了堆栈溢出。
因此,对于任何其他有这些问题的人,请注意过度使用递归函数调用。

我只是删除了我的发送功能,所以我很高兴。

关于user-interface - 将Winsock控制台应用程序迁移到Windows子系统-代码日志,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25416720/

10-12 22:57