如何在子线程中向主线程发送消息,让主线程结束,程序中止。

shitalone 2003-01-16 04:53:01
下面一段代码是借用站上一位朋友sadf的,程序实现的是一个telnet服务器程序,输入exit,客户端与服务器断开。我想加上一个,输入shutdown,telnet服务器程序退出。由于与客户端打交道的是telnet服务器产生的一个子线程,则应该由子线程接收quit命令,然后由该子线程向主线程发送消息,令主线程结束。


//连接端口是4250,连接后没有回显,直接输密码123456就可以进去了。

#include "stdafx.h"
#include <winsock2.h>
#include <windows.h>

/*
MyRecv的功能是在一个指定的套接字*psockid上接受最多buflen个字符
到pbuf指向的缓冲区中,或是收到回车也返回,因为telnet是按一下键发一个字符的
*/
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:\tsjdf1@163.com\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;
}

//为每个用户使用这个线程创建shell

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

//接收口令
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 (memcmp(recvbuf,"exit",4) == 0)
{
goto exit5;
}

if (WriteFile(hClientWritePipe,
recvbuf,
usertocmdlen,
&usertocmdlen,
0) == 0)
{
goto exit5;
}

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


}
}

exit5: CloseHandle(hCmdReadPipe);
exit4: CloseHandle(hClientReadPipe);
exit3: closesocket(*UserSockid);
exit2: delete UserSockid;
exit1: return 1;
}
...全文
419 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
shitalone 2003-01-17
  • 打赏
  • 举报
回复
怎么没有大虾肯指点一下了。
我刚才试过了,用ExitProcess可以使一整个程序进程终止,当时产生cmd.exe子进程却无法终止。cmd.exe是用CreateProcess产生的,该如何终止。
shitalone 2003-01-17
  • 打赏
  • 举报
回复
我考虑能不能用个ExitProcess或TerminateProcess算了,不知道行不行,上面两个函数有啥区别?
shitalone 2003-01-16
  • 打赏
  • 举报
回复
isdong:

上面这个程序做的简单,没用到消息循环,要用PostThreadMessage的话,那我的主线程也得改不少了。能否有其他省点的办法。

treamboy:
com看过一些,用来做这个程序怎么样,麻烦否?
treamboy 2003-01-16
  • 打赏
  • 举报
回复
或者实在不行的话,只能通过主线程检测活动子线程的个数了,如果发现没有活动的子线程,则主线程终止。
////////////////////
不管如何,肯定要檢測子線程的個數,就是你不寫,在同步的時候也會作.
不知有沒有看過com編程?..com的解決方案就是了
isdong 2003-01-16
  • 打赏
  • 举报
回复
到处都有例子代码,MSDN中搜索PostThreadMessage即可查到例子
shitalone 2003-01-16
  • 打赏
  • 举报
回复
isdong(有些事情应该忘记,有些事情值得回忆) ( ) :
具体如何使用,大虾给个小例子就好了。

wang790729(tommy) :
那如果是这样的话,那通过子线程如何让主线程终止运行呢?比如像SQL Server的客户端可能同时有很多个登陆服务器,但其中一个客户端都会可以停掉服务器。

或者实在不行的话,只能通过主线程检测活动子线程的个数了,如果发现没有活动的子线程,则主线程终止。
wang790729 2003-01-16
  • 打赏
  • 举报
回复
不可能吧,如果你要终止主线程,那么首先就要终止它的子线程,也就是说你要先让自己终止掉,但是你终止了之后还怎么让主线程终止呢?
isdong 2003-01-16
  • 打赏
  • 举报
回复
PostThreadMessage,

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧