|
![]() | 作者: tetley [tetley]
![]() |
登录 |
小弟正在学习WINSOCK, 有共同兴趣的不妨来探讨一下, 交流一下心得。也请各位斑竹来TEACH一下。 我现在的问题是如果不想WINDOW在等待时被锁定, 可以用多线程来实现,在每个线程中, 用accept新创的socket来处理data, 这个新socket可以设成WSAAsyncSelect(), 将处理过程交给窗口,这种方法不必规定SEND和RECV的运行顺序,每当SOCKET的buffer中有情况就按message的event进行处理; 也可以用普通的RECV或SEND 在线程中处理。第一种方法更灵活一点。问题是如果我想将多个socket交给window处理,(用WSAAsyncSelect()), 怎样才能区分是哪个SOCKET有FD EVENT发生呢? 除了多线程外,还有没有别的方法实现?And how to use select() to achieve the same purpose? |
地主 发表时间: 04-04-13 10:18 |
![]() | 回复: leonshoh [leonshoh] ![]() |
登录 |
用select模型呢 ? |
B1层 发表时间: 04-04-15 16:34 |
![]() | 回复: tetley [tetley] ![]() |
登录 |
select 也会锁定进程吧。 用select时, select检验那几个recv,send except 缓存,如果有信息, 就继续进行, 并刷新socket 组; 如果没信息就锁定等待timeval那么长的时间。 如果将timeval 设成 0, 就立即返回, 要用轮询来检验。 所以我就不理解为什么能用select可以不锁定window. 谁有例子给解释一下怎么用? |
B2层 发表时间: 04-04-16 21:34 |
![]() | 回复: tetley [tetley] ![]() |
登录 |
WSAAsyncSelect 中的 wMsg, 它注释的 -----通常,应用 程序需要将这个消息设为比Wi n d o w s的W M _ U S E R大的一个值,避免网络窗口消息与预定义 的标准窗口消息发生混淆与冲突 这是什么意思? WINDOWS的消息可以自己定义吗? |
B3层 发表时间: 04-04-16 23:01 |
![]() | 回复: sinister [sinister] ![]() |
登录 |
当然可以自定义消息。关于 select() 自己实践一下就全明白了。WSAAsyncSelect 你可以暂时这么理解,是 WINSOCK 在原有 BSD select() 上的又一层封状, |
B4层 发表时间: 04-04-17 19:45 |
![]() | 回复: tetley [tetley] ![]() |
登录 |
好, 试试看。 我用borland c++, 现在用多线程实现不锁定window, 用TThread. 我将send 和 recv 放到TThread 中的Execute中, 然后再主线程也就是window的线程中调用TThread. 但window还是锁定的呀? 谁能贴个例子, 看看标准的bcb多线程是怎么实现的? ![]() |
B5层 发表时间: 04-04-17 20:18 |
![]() | 回复: sinister [sinister] ![]() |
登录 |
如果要用 VCL 线程类,为何不去看它带的例子? 下面这两个测试代码我都不知道是几年 前写的了,写的非常之烂,只是能跑起来,就算有问题也不在提供任何支持了。只有读懂后 自行修改。 这个 select() 模型是 BCB 下编译的,用了 VCL 窗体,但没有用 TThread。 #define BUFFSIZE 1024 #define PORT 8888 #pragma pack(push, 1) typedef struct _SOCKETSTRU { SOCKET sckCreateSock; SOCKET sckNewSock; SOCKADDR_IN CreateSockIn; SOCKADDR_IN NewSockIn; FD_SET FdRead; FD_SET FdWrite; int nAddrLen; }SOCKETSTRU,* LPSOCKETSTRU; typedef struct _FILESTRUDATA { DWORD dwFalg; DWORD dwIsDir; TCHAR szFileName[MAX_PATH]; }FILEDATASTRU,* LPFILEDATASTRU; typedef struct _SENDFILESTRU { SOCKET Socket; TCHAR szFileName[MAX_PATH]; }SENDFILESTRU,* LPSENDFILESTRU; #pragma pack(pop) TCHAR g_szStruBuff[sizeof(FILEDATASTRU)]; TCHAR g_szBuffer[BUFFSIZE]; BOOL g_bIsRecv = FALSE; SOCKETSTRU g_ServerSockStru; SOCKETSTRU g_ClientSockStru; SENDFILESTRU g_SendFileStru; DWORD WINAPI ServerThread( LPVOID SOCKParam ) { int m_nRet; DWORD m_dwStruSize; HANDLE m_hFile; TCHAR szFileName[MAX_PATH]; DWORD m_dwWrite; FD_ZERO(&g_ServerSockStru.FdRead); FD_SET(g_ServerSockStru.sckCreateSock,&g_ServerSockStru.FdRead); while(TRUE) { m_nRet = select( g_ServerSockStru.sckCreateSock + 1, &g_ServerSockStru.FdRead, NULL, NULL, NULL ); if ( m_nRet == SOCKET_ERROR ) { Form1->Memo1->Lines->Add(WSAGetLastError()); closesocket(g_ServerSockStru.sckCreateSock); return FALSE; } if ( FD_ISSET(g_ServerSockStru.sckCreateSock,&g_ServerSockStru.FdRead) ) { g_ServerSockStru.nAddrLen = sizeof(g_ServerSockStru.NewSockIn); g_ServerSockStru.sckNewSock = accept( g_ServerSockStru.sckCreateSock, (LPSOCKADDR)&g_ServerSockStru.NewSockIn, &g_ServerSockStru.nAddrLen ); if ( g_ServerSockStru.sckNewSock == SOCKET_ERROR ) { closesocket(g_ServerSockStru.sckNewSock); return FALSE; } getpeername( g_ServerSockStru.sckCreateSock, (LPSOCKADDR)&g_ServerSockStru.NewSockIn, &g_ServerSockStru.nAddrLen ); Form1->Memo1->Lines->Add(inet_ntoa(g_ServerSockStru.NewSockIn.sin_addr)); FD_SET(g_ServerSockStru.sckNewSock,&g_ServerSockStru.FdRead); } if ( FD_ISSET(g_ServerSockStru.sckNewSock,&g_ServerSockStru.FdRead) ) { ZeroMemory(g_szBuffer,sizeof(g_szBuffer)); m_dwStruSize = recv(g_ServerSockStru.sckNewSock,g_szBuffer,BUFFSIZE,0); if ( m_dwStruSize == SOCKET_ERROR ) { closesocket(g_ServerSockStru.sckNewSock); CloseHandle(m_hFile); return FALSE; } else if ( (strncmp(g_szBuffer,"UPFILE_",lstrlen("UPFILE_"))) ==0 ) { wsprintf(szFileName,"c:\\%s",g_szBuffer); m_hFile = CreateFile( szFileName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE, (HANDLE)NULL ); if ( m_hFile == INVALID_HANDLE_VALUE ) { MessageBox(NULL,"Server Open File Error",NULL,MB_OK); return FALSE; } ZeroMemory(g_szBuffer,sizeof(g_szBuffer)); } else { WriteFile(m_hFile,g_szBuffer,m_dwStruSize,&m_dwWrite,NULL); } } } return TRUE; } DWORD WINAPI ClientThread(LPVOID SOCKParam) { int m_nRet; DWORD m_dwStruSize; HANDLE m_hFile; TCHAR szFileName[MAX_PATH]; DWORD m_dwWrite; while(TRUE) { FD_ZERO(&g_ClientSockStru.FdRead); FD_SET(g_ClientSockStru.sckCreateSock,&g_ClientSockStru.FdRead); m_nRet = select( g_ClientSockStru.sckCreateSock + 1, &g_ClientSockStru.FdRead, &g_ClientSockStru.FdWrite, NULL, NULL ); if ( m_nRet == SOCKET_ERROR ) { closesocket(g_ClientSockStru.sckCreateSock); return FALSE; } if ( FD_ISSET(g_ClientSockStru.sckCreateSock,&g_ClientSockStru.FdRead) ) { ZeroMemory(g_szBuffer,sizeof(g_szBuffer)); m_dwStruSize = recv(g_ClientSockStru.sckCreateSock,g_szBuffer,BUFFSIZE,0); if ( m_dwStruSize == SOCKET_ERROR ) { closesocket(g_ClientSockStru.sckCreateSock); CloseHandle(m_hFile); return FALSE; } else if ( (strncmp(g_szBuffer,"UPFILE_",lstrlen("UPFILE_"))) ==0 ) { wsprintf(szFileName,"c:\\%s",g_szBuffer); m_hFile = CreateFile( szFileName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE, (HANDLE)NULL ); if ( m_hFile == INVALID_HANDLE_VALUE ) { MessageBox(NULL,"Server Open File Error",NULL,MB_OK); return FALSE; } ZeroMemory(g_szBuffer,sizeof(g_szBuffer)); } else { WriteFile(m_hFile,g_szBuffer,m_dwStruSize,&m_dwWrite,NULL); } } } return TRUE; } BOOL WINAPI ServerInitSocket() { WORD wVersionRequested = MAKEWORD(1,1); WSADATA WSAData; BOOL m_bFlag = TRUE; int m_nErr; HANDLE m_hThread; DWORD m_dwThreadID; m_nErr = WSAStartup(wVersionRequested,&WSAData); if ( m_nErr != 0 ) { return FALSE; } g_ServerSockStru.sckCreateSock = socket (AF_INET,SOCK_STREAM,0); if ( g_ServerSockStru.sckCreateSock == SOCKET_ERROR ) { closesocket(g_ServerSockStru.sckCreateSock); return FALSE; } g_ServerSockStru.CreateSockIn.sin_family = AF_INET; g_ServerSockStru.CreateSockIn.sin_port = htons(PORT); g_ServerSockStru.CreateSockIn.sin_addr.s_addr = htonl(INADDR_ANY); m_nErr = setsockopt( g_ServerSockStru.sckCreateSock, SOL_SOCKET, SO_REUSEADDR, (LPCTSTR) &m_bFlag, sizeof(m_bFlag) ); if ( m_nErr == SOCKET_ERROR ) { closesocket(g_ServerSockStru.sckCreateSock); return FALSE; } m_nErr = bind( g_ServerSockStru.sckCreateSock, (LPSOCKADDR)&g_ServerSockStru.CreateSockIn, sizeof(g_ServerSockStru.CreateSockIn) ); if ( m_nErr == SOCKET_ERROR ) { closesocket(g_ServerSockStru.sckCreateSock); return FALSE; } m_nErr = listen(g_ServerSockStru.sckCreateSock,1); if ( m_nErr == SOCKET_ERROR ) { Form1->Memo1->Lines->Add("listen error!"); closesocket(g_ServerSockStru.sckCreateSock); return FALSE; } Form1->Memo1->Lines->Add("listen ok!"); m_hThread = CreateThread( NULL, 0, ServerThread, (LPVOID)0, 0, &m_dwThreadID ); CloseHandle(m_hThread); return TRUE; } BOOL WINAPI ClientInitSocket(LPCTSTR lpAddress) { WORD wVersionRequested = MAKEWORD(1,1); WSADATA WSAData; int m_nErr; HANDLE m_hThread; DWORD m_dwThreadID; m_nErr = WSAStartup(wVersionRequested,&WSAData); if ( m_nErr != 0 ) { return FALSE; } g_ClientSockStru.sckCreateSock = socket (AF_INET,SOCK_STREAM,0); if ( g_ClientSockStru.sckCreateSock == SOCKET_ERROR ) { closesocket(g_ClientSockStru.sckCreateSock); return FALSE; } g_ClientSockStru.CreateSockIn.sin_family = AF_INET; g_ClientSockStru.CreateSockIn.sin_port = htons(PORT); g_ClientSockStru.CreateSockIn.sin_addr.s_addr = inet_addr(lpAddress); m_nErr = connect( g_ClientSockStru.sckCreateSock, (LPSOCKADDR)&g_ClientSockStru.CreateSockIn, sizeof(g_ClientSockStru.CreateSockIn) ); if ( m_nErr == SOCKET_ERROR ) { closesocket(g_ClientSockStru.sckCreateSock); return FALSE; } m_hThread = CreateThread( NULL, 0, ClientThread, (LPVOID)0, 0, &m_dwThreadID ); CloseHandle(m_hThread); return TRUE; } 这个是 WINSOCK 的 WSAAsyncSelect(),纯 SDK 做的。 BOOL WINAPI InitSocket(HWND hWnd) { if((WSAStartup(dwVersion,&wsaData))!=0) { MessageBox(hWnd,"INIT SOCKET ERROR",NULL,MB_OK); return FALSE; } CreateSock=socket(AF_INET,SOCK_STREAM,0); if(CreateSock==SOCKET_ERROR) { closesocket(CreateSock); MessageBox(hWnd,"SOCKET ERROR",NULL,MB_OK); return FALSE; } Sock_in.sin_family=AF_INET; Sock_in.sin_port=htons(PORT); Sock_in.sin_addr.S_un.S_addr=htonl(INADDR_ANY); setsockopt(CreateSock,SOL_SOCKET,SO_REUSEADDR,(LPTSTR)&dwFlag,sizeof(dwFlag)); if(bind(CreateSock,(LPSOCKADDR)&Sock_in,sizeof(Sock_in))==SOCKET_ERROR) { closesocket(CreateSock); TCHAR szTempMsg[MAX_PATH ] = "0"; wsprintf(szTempMsg,"BIND ERROR %d",WSAGetLastError()); MessageBox(hWnd,szTempMsg,NULL,MB_OK); return FALSE; } else if(listen(CreateSock,3)==SOCKET_ERROR) { closesocket(CreateSock); MessageBox(hWnd,"LISTEN ERROR",NULL,MB_OK); return FALSE; } else if(WSAAsyncSelect(CreateSock,hWnd,WM_SOCKET,FD_ACCEPT|FD_CLOSE)==SOCKET_ERROR) { closesocket(CreateSock); MessageBox(hWnd,"WSASelect ERROR",NULL,MB_OK); return FALSE; } addrlen=sizeof(SOCKADDR_IN); return TRUE; } //--------------------------------------------------------------------------- LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { static TCHAR szCommand[dwComm]; static TCHAR szExec[dwComm]; switch(message) { case WM_SOCKET: if(WSAGETSELECTERROR(lParam)) { closesocket(wParam); break; } switch(WSAGETSELECTEVENT(lParam)) { //连接 case FD_ACCEPT: NewSock=accept(CreateSock,(LPSOCKADDR)&NewSock_in,&addrlen); WSAAsyncSelect(NewSock,hWnd,WM_SOCKET,FD_READ|FD_WRITE|FD_CLOSE); break; //读取输入,如是回车则执行命令 //不是将输入复制到缓冲区 case FD_READ: ZeroMemory(szCommand,dwComm); recv(NewSock,szCommand,dwComm,0); if(szCommand[0]==VK_RETURN) { wsprintf(szCommand,"\n\n\r%s",PROMPT); send(NewSock,szCommand,dwComm,0); ExeCommand(szExec,hWnd); ZeroMemory(szExec,dwComm); } else lstrcat(szExec,szCommand); send(NewSock,szCommand,dwComm,0); break; case FD_CLOSE: closesocket(wParam); break; } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd,message,wParam,lParam); } return 0; } |
B6层 发表时间: 04-04-17 23:46 |
![]() | 回复: tetley [tetley] ![]() |
登录 |
sinister写的很清楚呀, 谢谢了![]() 原来光用select并不能nonblock住window,必须和多线程结合在一起才能实现不block window.对不对呀? 我现在用的这个bcb没有帮助文件, 哪里有下载的? 谢谢, 找了许久找不到。 还有,你说 --就算有问题也不在提供任何支持了-- 是什么意思, 在编写这类程序时应当注意什么? [此贴被 tetley(tetley) 在 04月18日19时10分 编辑过] |
B7层 发表时间: 04-04-18 19:07 |
![]() | 回复: tetley [tetley] ![]() |
登录 |
我试了试select().用的TThread. 我将serverThread() 中的内容加在TThread中的Execute()中, 将ServerInitSocket()中的内容加在TThread中的构造函数中,并将Execute()加在了构造中。 然后我在窗口中加了一个按钮, 在里面调用了 多线程, 问题是 我按了按钮后, 主窗口还是锁定的, 所有别的按钮都不能用了。为什么? ![]() |
B8层 发表时间: 04-04-18 23:28 |
![]() | 回复: sinister [sinister] ![]() |
登录 |
本身用 select() 就是为了区别于 新建一个 SOCKET 就开一个线程的方法。 select() 完全 可以不用多线程。 之所以在 ServerInitSocket 开始建立一个线程是为了,不让窗体锁定。 这个构价根本不需要 VCL TThread。你放一个 TBUTTON 然后在其直接调用 ServerInitSocket() 即可。还有,你能确保不是你新添加代码的问题吗?调试了吗?跟踪了吗? 我说不提供支持,是说代码虽然以跑起来,但并不是我在产品或项目中使用的,并没有经过 严格的测试。只是一个框架,其余的东西还是要靠自己调试。我感觉你好象从不仔细调试、 跟踪程序,也不仔细去搜索相关文挡,遇见问题马上就贴上来了。 |
B9层 发表时间: 04-04-19 20:54 |
![]() | 回复: tetley [tetley] ![]() |
登录 |
多谢批评指导![]() ![]() 我也觉得我的编程风格方法有问题, 因为从来没有特意跟踪调试过。 不过我很喜欢编程的, 希望大家多多批评指导 ![]() 不过我查资料老是查不到关键的, 比如说select, 我查到的全是大同小异, 在看了sinister的例子后才了解清楚是怎么一回事, 可能是我的理解能力不好吧。 ![]() ![]() 希望大家指导一些学习方法。 ![]() ![]() |
B10层 发表时间: 04-04-20 05:19 |
![]() | 回复: tetley [tetley] ![]() |
登录 |
好了, 终于都工作正常了。![]() |
B11层 发表时间: 04-04-21 22:24 |
|
20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon
粤ICP备05087286号