论坛: 编程破解 标题: 有兴趣的来讨论一下WINSOCK问题 复制本贴地址    
作者: 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号