【问题标题】:_popen crash[Windows - C]_popen 崩溃[Windows - C]
【发布时间】:2013-10-15 19:49:57
【问题描述】:

我是 C 的新手(实际上是所有编译语言),下面你会看到我可怕的代码,我尝试接收命令,然后我希望执行它(尚未实现)。

我从 Microsoft 获取了 _popen 函数上的示例代码并对其进行了修改(非常轻微),但由于某种原因,它在收到命令后使我的程序崩溃。如果我将此代码块移到命令接收器部分上方,它就可以正常工作。我是在覆盖另一个内存地址还是什么?

如果您需要服务器(用 python 编写),请告诉我。希望你能帮助有需要的菜鸟。

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

int sendall(int sock, char *message, unsigned int size);
int connect(char address[], short port);
char* recvall(int sock, unsigned int *msgsize);


int main(){
    char address[] = "127.0.0.1";
    short port = 1234;
    int wait = 5000;

    //Connect back
    int sock = 1;
    printf("Connecting...\n");
    sock = connect(address, port);
    while(sock == 1){
        WSACleanup();
        Sleep(wait);
        sock = connect(address, port);
    }

    printf("Succesfully conneted\n");

    char test[] = "ABCDEFGH";
    sendall(sock,test, 8);

    unsigned int msgsize;
    char *msg = recvall(sock,&msgsize);


    printf("%s\n", msg);
    printf("%d\n", msgsize);


    //RUN COMMAND

    char   psBuffer[128];
    FILE   *pPipe;


    printf("There\n");

    if( (pPipe = _popen( "ipconfig", "rt" )) == NULL )
        exit( 1 );

    printf("Out\n");

    while(fgets(psBuffer, 128, pPipe)){
        printf(psBuffer);
    }


    if (feof( pPipe)){
        printf( "\nProcess returned %d\n", _pclose( pPipe ) );
    }else{
        printf( "Error: Failed to read the pipe to the end.\n");
    }

    //RUN COMMAND END 

    Sleep(10000);
    return 0;
}

int sendall(int sock, char *message, unsigned int size){

    //Send size packet
    char sizepacket[12];
    sprintf (sizepacket, "%012u",size);
    send(sock, sizepacket, 12, 0);

    //Send data
    unsigned int left = size;
    unsigned int offset = 0;
    while(left>0){
        if(left<1024){
            send(sock, (message+offset), left, 0);
            left = 0;
        }else{
            send(sock, (message+offset), 1024, 0);
            offset = offset + 1024;
            left = left - 1024;
        }
    }
    return 0;
}

char* recvall(int sock, unsigned int *size){
    char *message;

    //Get size packet
    char sizebuff[24];
    memset (&sizebuff,0,24);
    recv(sock, sizebuff, 12, 0);
    *size = atoi(sizebuff);

    //Alloc space for message
    message = (char*)  malloc(*size + 1);
    memset(message,0,1024);

    //Get data
    unsigned int left = *size;
    unsigned int offset = 0;
    while(left>0){
        if(left<1024){
            recv(sock, (message+offset), left, 0);
            left = 0;
        }else{
            recv(sock, (message+offset), 1024, 0);
            offset = offset + 1024;
            left = left - 1024;
        }
    }
    return message;
}



int connect(char address[], short port){
    int returnvalue;

    WSADATA wsaData;

    returnvalue = WSAStartup(MAKEWORD(2,2), &wsaData);
    if(returnvalue != 0){
        return 1;
    }

    int sock;
    sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(sock == 0){
        return 1;
    }


    //Create struct
    struct sockaddr_in clientService;
    clientService.sin_family = AF_INET;
    clientService.sin_addr.s_addr = inet_addr(address);
    clientService.sin_port = htons(port);


    returnvalue = connect(sock, (SOCKADDR*) &clientService, sizeof(clientService));
    if (returnvalue != 0){
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    return sock;
}

【问题讨论】:

    标签: c windows sockets popen


    【解决方案1】:

    您的 popen 似乎并不依赖于您的套接字通信。

    请描述您的服务器发送的消息(hexdump?)

    请查看您的 recvall() 函数。您从套接字读取 12 个字节,将其转换为 int,然后 malloc 那么多字节,将其存储到 *size,然后 memset 消息缓冲区(只是 malloc'ed)的大小为 1024。然后您将消息接收到缓冲区,但不放置任何保护措施,以确保您不会超出 message[*size] 的结尾。

    int main(){
        //...
        unsigned int msgsize;
        char *msg = recvall(sock,&msgsize);
        printf("%d\n", msgsize);
        printf("%s\n", msg);
        return 0;
    }
    
    char* recvall(int sock, unsigned int *size){
        char *message;
        //Get size packet
        char sizebuff[24];
        memset (&sizebuff,0,24);
        recv(sock, sizebuff, 12, 0);
        *size = atoi(sizebuff);
        printf("size: %d\n",*size);fflush(stdout);
        //Alloc space for message
        message = (char*)  malloc(*size + 1);
        memset(message,0,1024); //why 1024? why not *size?
        //Get data
        unsigned int left = *size;
        unsigned int offset = 0;
        while(left>0){
            if(left<1024){
                recv(sock, (message+offset), left, 0);
                left = 0;
            }else{
                recv(sock, (message+offset), 1024, 0); //why 1024?
                offset = offset + 1024; //again, why 1024?, this is > 1024
                left = left - 1024;
            }
        }
        return message;
    }
    

    【讨论】:

    • 我觉得自己太蠢了……我猜是第一步。您对前 1024 条是正确的 - 最后一条是因为我收到了 1024 字节块的消息,但它现在可以完美编译。非常感谢!
    【解决方案2】:

    您的示例无法在我的系统上编译,因为您有两个版本的 connect() 函数 - 您的本地调用和系统版本,从您的本地 connect() 函数本身在此行中调用:

    returnvalue = connect(sock, (SOCKADDR*) &clientService, sizeof(clientService));
    

    尝试将您的本地版本更改为其他名称,例如xconnect()。我很惊讶你的编译器允许这样做。

    【讨论】:

    • 虽然它被标记为 C,但 OP 很可能将程序编译为 C++,在这种情况下,这不是问题(两个连接函数具有不同的签名)。
    • @Mark Wilkins -- 谢谢。你可能是对的。我考虑过这一点,但我没有在代码中看到任何“这显然是 C++”的语法,而且 OP 声称正在使用 C(尽管是公认的新手)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多