VC驿站

 找回密码
 加入驿站

QQ登录

只需一步,快速开始

搜索
查看: 21513|回复: 312
打印 上一主题 下一主题

[交流] WinSocket模型的探讨——select模型,认为这篇文章很不错。因此转载了。

  [复制链接]
15_avatar_middle
最佳答案
0 
跳转到指定楼层
1#
在线会员 发表于 2010-10-3 11:39:55 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 360737395 于 2010-10-9 09:27 编辑

查找了很多资料都找不到select模型的详细用法,《Windows网络必威官方》这本书上也只是写了一个简单的回应服务器,就连writefds的用法都没讲,也不知道什么时候利用“可写”来发文件。这些都是我的疑问,相信很多研究网络必威官方的同路人也碰到了我的这些问题。这些疑问在这篇文章中都解决了!耗费了偶很多的精力去猜测去思考!
游客,如果您要查看本帖隐藏内容请回复




上一篇:SDL入门教程
下一篇:异步套接字基础:select函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET
33_avatar_middle
最佳答案
0 
2#
在线会员 发表于 2010-10-3 12:28:34 | 只看该作者
沙发,支持楼主~~
46_avatar_middle
最佳答案
0 
3#
在线会员 发表于 2010-10-3 13:09:55 | 只看该作者
网络必威官方是个难点~WinSocket模型的探讨——select模型,认为这篇文章很不错。因此转载了。
15_avatar_middle
最佳答案
0 
4#
ico_lz  楼主| 发表于 2010-10-3 13:31:50 | 只看该作者
就是难才好玩。。这篇文章还讲了 文件共享的问题。。
28_avatar_middle
最佳答案
0 
5#
在线会员 发表于 2010-10-3 16:57:19 | 只看该作者
WinSocket模型的探讨——select模型,认为这篇文章很不错。因此转载了。  多谢分享
69_avatar_middle
最佳答案
0 
6#
在线会员 发表于 2010-10-3 22:01:50 | 只看该作者
瞧一瞧,是不是真的有那么好
35_avatar_middle
最佳答案
0 
7#
在线会员 发表于 2010-10-3 22:39:16 | 只看该作者
貌似不错。。。
04_avatar_middle
最佳答案
0 
8#
在线会员 发表于 2010-10-3 23:13:27 | 只看该作者
什么文章这么好?
78_avatar_middle
最佳答案
0 
9#
在线会员 发表于 2010-10-4 06:52:14 | 只看该作者
谢谢 并且拿走了
11_avatar_middle
最佳答案
0 
10#
在线会员 发表于 2010-10-7 13:49:05 | 只看该作者
我先看一下 学习
87_avatar_middle
最佳答案
0 
11#
在线会员 发表于 2010-10-7 14:20:18 | 只看该作者
沙发,支持楼主~~
15_avatar_middle
最佳答案
0 
12#
ico_lz  楼主| 发表于 2010-10-9 09:28:05 | 只看该作者
/**********************************************************************************************************************/

第二个文件

/*/
文件:SocketClient.cpp

说明:
此文件是作为测试的客户端,实现了登录和取文件的功能。
和服务端的交互就是采用了发送命令、数据长度,然后发送具体的数据这样的顺序。
详细可看服务端的说明。

基本逻辑是这样的,客户端要先登录服务端,然后登录成功之后,才能进行相应的操作。

错误处理做得不太好,以后再补充了。

其他的如注释,结构,命名等的编码规范都用了个人比较喜欢的方式。

输出:
..\Bin\SocketClient.exe

用法:
可以 SocketClient Server_IP
或者直接启动SocketClient,会提示你输入服务端的IP

Todo:
下一步首先完成各个SOCKET的模型,然后公开自己的研究代码。
功能方面就是:
1、服务器可以指定共享文件夹
2、客户端可以列出服务器共享了哪些文件
3、客户端可以列出哪些用户在线,并可以发命令和其他用户聊天
/*/

  1. #include <winsock2.h>
  2. #pragma comment(lib, "WS2_32")

  3. #include <iostream>
  4. using namespace std;

  5. #include <stdlib.h>

  6. #include "..\Common Include\CommonSocket.h"
  7. #include "..\Common Include\CommonCmd.h"

  8. bool g_bAuth = false;

  9. void GetFile(SOCKET sock);
  10. bool Auth(SOCKET sock, char *szName, char *szPwd);
  11. bool RegisterUser(SOCKET sock, char *szName, char *szPwd);


  12. ///////////////////////////////////////////////////////////////////////
  13. //
  14. // 函数名       : Usage
  15. // 功能描述     : 提示程序用法
  16. // 返回值       : void
  17. //
  18. ///////////////////////////////////////////////////////////////////////
  19. void Usage()
  20. {
  21. printf("*******************************************\n");
  22. printf("Socket Client                            \n");
  23. printf("Written by DYL                         \n");
  24. printf("Email: dylgsy@163.com                 \n");
  25. printf("Usage: SocketClient.exe Server_IP          \n");
  26. printf("*******************************************\n");
  27. }


  28. ///////////////////////////////////////////////////////////////////////
  29. //
  30. // 函数名       : Menu
  31. // 功能描述     : 选择服务的界面
  32. // 返回值       : void
  33. //
  34. ///////////////////////////////////////////////////////////////////////
  35. void Menu()
  36. {
  37. system("cls");
  38. printf("********************************************\n");
  39. printf("请选择操作:        \n\n");
  40. printf("1、取得文件         \n");
  41. printf("2、退出          \n");
  42. printf("********************************************\n");
  43. }


  44. ///////////////////////////////////////////////////////////////////////
  45. //
  46. // 函数名       : LoginMenu
  47. // 功能描述     : 用户登录的界面
  48. // 返回值       : void
  49. //
  50. ///////////////////////////////////////////////////////////////////////
  51. void LoginMenu()
  52. {
  53. cout << "请按任意键继续操作." <<endl;
  54. getchar();
  55. system("cls");
  56. printf("********************************************\n");
  57. printf("请选择操作:        \n\n");
  58. printf("1、登录          \n");
  59. printf("2、注册          \n");
  60. printf("3、退出          \n");
  61. printf("********************************************\n");
  62. }


  63. ///////////////////////////////////////////////////////////////////////
  64. //
  65. // 函数名       : Login
  66. // 功能描述     : 用户登录的界面逻辑
  67. // 参数         : SOCKET sock
  68. // 返回值       : bool
  69. //
  70. ///////////////////////////////////////////////////////////////////////
  71. bool Login(SOCKET sock)
  72. {
  73. bool bGoOn = true;
  74. while(bGoOn)
  75. {
  76.   LoginMenu();
  77.   int nChoose = 0;
  78.   cin >> nChoose;

  79.   char szName[10];
  80.   char szPwd[20];
  81.   char szConfirmPwd[20];
  82.   memset(szName, 0, 10);
  83.   memset(szPwd, 0, 20);
  84.   memset(szConfirmPwd, 0, 20);

  85.   bool bGoOnLogin = true;

  86.   switch(nChoose)
  87.   {
  88.   case 1:
  89.    while(bGoOnLogin)
  90.    {
  91.     cout << "请输入你的用户名:";
  92.     cin >> szName;
  93.     cout << "请输入你的密码:";
  94.     cin >> szPwd;
  95.     if(Auth(sock, szName, szPwd))
  96.     {
  97.      return true;
  98.     }
  99.     else
  100.     {
  101.      char c;
  102.      cout << "继续登录?y/n" << endl;
  103.      cin >> c;
  104.      switch(c)
  105.      {
  106.      case 'y':
  107.       bGoOnLogin = true;
  108.       break;
  109.      case 'n':
  110.       bGoOnLogin = false;
  111.       break;
  112.      default:
  113.       break;
  114.      }
  115.     }
  116.    }
  117.    break;
  118.    
  119.   case 2:
  120.    cout << "请输入你的用户名:";
  121.    cin >> szName;
  122.    cout << "请输入你的密码:";
  123.    cin >> szPwd;
  124.    cout << "请再次输入你的密码:";
  125.    cin >> szConfirmPwd;
  126.    if(strcmp(szPwd, szConfirmPwd) != 0)
  127.    {
  128.     cout << "前后密码不一致" << endl;
  129.    }
  130.    else
  131.    {
  132.     if(!RegisterUser(sock, szName, szPwd))
  133.     {
  134.      cout << "注册用户失败!" << endl;
  135.     }
  136.    }
  137.    break;

  138.   case 3:
  139.    bGoOn = false;
  140.    return false;
  141.   default:
  142.    break;
  143.   }
  144. }

  145. return false;
  146. }

  147. void main(int argc, char *argv[])
  148. {
  149. system("cls");
  150. char szServerIP[20];
  151. memset(szServerIP, 0, 20);

  152. if(argc != 2)
  153. {
  154.   cout << "请输入服务器IP:";
  155.   cin >> szServerIP;
  156. }
  157. else
  158. {
  159.   strcpy(szServerIP, argv[1]);
  160. }
  161. InitWinsock();
  162. SOCKET sockServer;
  163. sockServer = ConnectServer(szServerIP, PORT, 1);
  164. if(sockServer == NULL)
  165. {
  166.   OutErr("连接服务器失败!");
  167.   return;
  168. }
  169. else
  170. {
  171.   OutMsg("已和服务器建立连接!");
  172. }

  173. // 要求用户登录
  174. if(!Login(sockServer))
  175.   return;

  176. // 登录成功,让用户选择服务
  177. int nChoose = 0;
  178. bool bExit = false;
  179. while(!bExit)
  180. {
  181.   Menu();
  182.   cin >> nChoose;
  183.   switch(nChoose)
  184.   {
  185.   case 1:  // 获取文件
  186.    GetFile(sockServer);
  187.    break;
  188.   case 2:
  189.    bExit = true;
  190.    break;   
  191.   default:
  192.    break;
  193.   }
  194. }
  195. shutdown(sockServer, SD_BOTH);
  196. closesocket(sockServer);

  197. }


  198. ///////////////////////////////////////////////////////////////////////
  199. //
  200. // 函数名       : Auth
  201. // 功能描述     : 用户登录认证
  202. // 参数         : SOCKET sock
  203. // 参数         : char *szName
  204. // 参数         : char *szPwd
  205. // 返回值       : bool
  206. //
  207. ///////////////////////////////////////////////////////////////////////
  208. bool Auth(SOCKET sock, char *szName, char *szPwd)
  209. {
  210. char szCmd[50];
  211. memset(szCmd, 0, 50);
  212. strcpy(szCmd, szName);
  213. strcat(szCmd, " ");
  214. strcat(szCmd, szPwd);

  215. SCommand cmd;
  216. cmd.CommandID = CMD_AUTHEN;
  217. cmd.DataSize = strlen(szCmd);

  218. int nRet;
  219. nRet = SendFix(sock, (char *)&cmd, sizeof(cmd));
  220. if(nRet == SOCKET_ERROR)
  221. {
  222.   OutErr("SendFix() failed!");
  223.   return false;
  224. }
  225. else
  226. {
  227.   SendFix(sock, szCmd, strlen(szCmd));
  228.   char szBuf[10];
  229.   memset(szBuf, 0, 10);
  230.   recv(sock, szBuf, 10, 0);
  231.   if(strcmp(szBuf, "UP OK!") == 0)
  232.   {
  233.    cout << "登录成功。" << endl;
  234.    g_bAuth = true;
  235.   }
  236.   else if(strcmp(szBuf, "U Err!") == 0)
  237.   {
  238.    cout << "此用户不存在。" << endl;
  239.    g_bAuth = false;
  240.   }
  241.   else if(strcmp(szBuf, "P Err!") == 0)
  242.   {
  243.    cout << "密码错误。" << endl;
  244.    g_bAuth = false;
  245.   }
  246. }
  247. return g_bAuth;
  248. }


  249. ///////////////////////////////////////////////////////////////////////
  250. //
  251. // 函数名       : GetFile
  252. // 功能描述     : 取得服务器的文件
  253. // 参数         : SOCKET sock
  254. // 返回值       : void
  255. //
  256. ///////////////////////////////////////////////////////////////////////
  257. void GetFile(SOCKET sock)
  258. {
  259. if(!g_bAuth)
  260. {
  261.   OutMsg("用户还没登录!请先登录");
  262.   return;
  263. }

  264. char szSrcFile[MAX_PATH];
  265. char szDstFile[MAX_PATH];
  266. memset(szSrcFile, 0, MAX_PATH);
  267. memset(szDstFile, 0, MAX_PATH);

  268. cout << "你要取得Server上的文件:";
  269. cin >> szSrcFile;

  270. cout << "你要把文件存在哪里:";
  271. cin >> szDstFile;

  272. SCommand cmd;
  273. cmd.CommandID = CMD_GETFILE;
  274. cmd.DataSize = strlen(szSrcFile);

  275. // 发送命令
  276. SendFix(sock, (char *)&cmd, sizeof(cmd));

  277. // 发送文件名
  278. SendFix(sock, szSrcFile, strlen(szSrcFile));

  279. // 接收文件长度
  280. DWORD dwFileSize = 0;
  281. RecvFix(sock, (char*)&dwFileSize, sizeof(dwFileSize));

  282. if(dwFileSize == 0)
  283. {
  284.   OutMsg("文件不存在");
  285.   return;
  286. }

  287. // 接收文件内容
  288. DWORD dwLeft = dwFileSize;
  289. char szBuf[1024];
  290. HANDLE hFile = CreateFile(szDstFile, GENERIC_WRITE, FILE_SHARE_READ,
  291.   NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  292. if(hFile == INVALID_HANDLE_VALUE)
  293. {
  294.   hFile = CreateFile(szDstFile, GENERIC_WRITE, FILE_SHARE_READ,
  295.    NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
  296.   if(hFile == INVALID_HANDLE_VALUE)
  297.   {
  298.    OutErr("CreateFile failed!");
  299.    return;
  300.   }
  301. }
  302. while(dwLeft > 0)
  303. {
  304.   memset(szBuf, 0, 1024);
  305.   // 这里是不确定文件内容的,所以要用recv,不能用RecvFix
  306.   int nRead = recv(sock, szBuf, 1024, 0);
  307.   if(nRead == SOCKET_ERROR)
  308.    OutErr("RecvFix Error!");

  309.   DWORD dwWritten = 0;
  310.   if(!WriteFile(hFile, szBuf, nRead, &dwWritten, NULL))
  311.   {
  312.    OutErr("WriteFile error!");
  313.    return;
  314.   }
  315.   dwLeft -= dwWritten;
  316. }

  317. CloseHandle(hFile);

  318. OutMsg("接收文件成功!");
  319. }


  320. ///////////////////////////////////////////////////////////////////////
  321. //
  322. // 函数名       : RegisterUser
  323. // 功能描述     : 注册新用户
  324. // 参数         : SOCKET sock
  325. // 参数         : char *szName
  326. // 参数         : char *szPwd
  327. // 返回值       : bool
  328. //
  329. ///////////////////////////////////////////////////////////////////////
  330. bool RegisterUser(SOCKET sock, char *szName, char *szPwd)
  331. {
  332. char szCmd[50];
  333. memset(szCmd, 0, 50);
  334. strcpy(szCmd, szName);
  335. strcat(szCmd, " ");
  336. strcat(szCmd, szPwd);

  337. SCommand cmd;
  338. cmd.CommandID = CMD_REGISTER;
  339. cmd.DataSize = strlen(szCmd);

  340. // 发送命令
  341. int nRet = SendFix(sock, (char *)&cmd, sizeof(cmd));
  342. if(nRet == SOCKET_ERROR)
  343. {
  344.   OutErr("SendFix() failed!");
  345.   return false;
  346. }
  347. else
  348. {
  349.   // 发送用户名和密码串
  350.   SendFix(sock, szCmd, strlen(szCmd));
  351.   char szBuf[10];
  352.   memset(szBuf, 0, 10);
  353.   
  354.   recv(sock, szBuf, 10, 0);
  355.   if(strcmp(szBuf, "REG OK!") == 0)
  356.   {
  357.    cout << "注册成功。" << endl;
  358.    return true;
  359.   }
  360.   else if(strcmp(szBuf, "REG ERR!") == 0)
  361.   {
  362.    cout << "注册失败." << endl;
  363.    return false;
  364.   }
  365. }

  366. return false;
  367. }
复制代码
15_avatar_middle
最佳答案
0 
13#
ico_lz  楼主| 发表于 2010-10-9 09:28:23 | 只看该作者
/**********************************************************************************************************************/

第三个文件,公用的

/*/
文件: CommonSocket.h
说明:
实现了服务端和客户端一些公用的函数!
/*/

  1. #ifndef __COMMONSOCKET_H__
  2. #define __COMMONSOCKET_H__

  3. #include <iostream>
  4. using namespace std;

  5. #define OutErr(a) cout << (a) << endl \
  6.       << "出错代码:" << WSAGetLastError() << endl \
  7.       << "出错文件:" << __FILE__ << endl  \
  8.       << "出错行数:" << __LINE__ << endl \

  9. #define OutMsg(a) cout << (a) << endl;

  10. ///////////////////////////////////////////////////////////////////////
  11. //
  12. // 函数名       : InitWinsock
  13. // 功能描述     : 初始化WINSOCK
  14. // 返回值       : void
  15. //
  16. ///////////////////////////////////////////////////////////////////////
  17. void InitWinsock()
  18. {
  19. // 初始化WINSOCK
  20. WSADATA wsd;
  21. if( WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
  22. {
  23.   OutErr("WSAStartup()");
  24. }
  25. }

  26. ///////////////////////////////////////////////////////////////////////
  27. //
  28. // 函数名       : ConnectServer
  29. // 功能描述     : 连接SERVER
  30. // 参数         : char *lpszServerIP IP地址
  31. // 参数         : int nPort    端口
  32. // 返回值       : SOCKET    SERVER 的 Socket
  33. //
  34. ///////////////////////////////////////////////////////////////////////
  35. SOCKET ConnectServer(char *lpszServerIP, int nPort, ULONG NonBlock)
  36. {
  37. SOCKET sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  38. //ioctlsocket(sServer, FIONBIO, &NonBlock);

  39. struct hostent *pHost = NULL;
  40. struct sockaddr_in servAddr;
  41. servAddr.sin_family = AF_INET;
  42. servAddr.sin_port = htons(nPort);
  43. servAddr.sin_addr.s_addr = inet_addr(lpszServerIP);


  44. // 如果给的是主机的名字而不是IP地址
  45. if(servAddr.sin_addr.s_addr == INADDR_NONE)
  46. {
  47.   pHost = gethostbyname( lpszServerIP );
  48.   if(pHost == NULL)
  49.   {
  50.    OutErr("gethostbyname Failed!");
  51.    return NULL;
  52.   }
  53.   memcpy(&servAddr.sin_addr, pHost->h_addr_list[0], pHost->h_length);
  54. }

  55. int nRet = 0;
  56. nRet = connect(sServer, (struct sockaddr *)&servAddr, sizeof(servAddr));
  57. if( nRet == SOCKET_ERROR )
  58. {
  59.   OutErr("connect failed!");
  60.   return NULL;
  61. }
  62.   
  63. return sServer;
  64. }

  65. ///////////////////////////////////////////////////////////////////////
  66. //
  67. // 函数名       : BindServer
  68. // 功能描述     : 绑定端口
  69. // 参数         : int nPort
  70. // 返回值       : SOCKET
  71. //
  72. ///////////////////////////////////////////////////////////////////////
  73. SOCKET BindServer(int nPort)
  74. {
  75. // 创建socket
  76. SOCKET sServer = socket(AF_INET, SOCK_STREAM, 0);

  77. // 绑定端口
  78. struct sockaddr_in servAddr;
  79. servAddr.sin_family = AF_INET;
  80. servAddr.sin_port = htons(nPort);
  81. servAddr.sin_addr.s_addr = htonl(INADDR_ANY);

  82. if(bind(sServer, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0)
  83. {
  84.   OutErr("bind Failed!");
  85.   return NULL;
  86. }

  87. // 设置监听队列为200
  88. if(listen(sServer, 200) != 0)
  89. {
  90.   OutErr("listen Failed!");
  91.   return NULL;
  92. }
  93. return sServer;
  94. }


  95. ///////////////////////////////////////////////////////////////////////
  96. //
  97. // 函数名       : AcceptClient
  98. // 功能描述     :
  99. // 参数         : SOCKET sServer [in]
  100. // 参数         : LPSTR lpszIP  [out] 返回客户端的IP地址
  101. // 返回值       : SOCKET   [out] 返回客户端的socket
  102. //
  103. ///////////////////////////////////////////////////////////////////////
  104. SOCKET AcceptClient(SOCKET sListen, LPSTR lpszIP)
  105. {
  106. struct sockaddr_in cliAddrTmp;
  107. int cliAddrSize = sizeof(struct sockaddr_in);
  108. SOCKET sClient = accept(sListen, (struct sockaddr *)&cliAddrTmp, &cliAddrSize);
  109. if(sClient == INVALID_SOCKET)
  110. {
  111.   OutErr("accept failed!");
  112.   return NULL;
  113. }
  114. sprintf(lpszIP, "%s", inet_ntoa(cliAddrTmp.sin_addr));

  115. return sClient;
  116. }

  117. ///////////////////////////////////////////////////////////////////////
  118. //
  119. // 函数名       : RecvFix
  120. // 功能描述     : 接收指定长度的数据,考虑非阻塞socket的情况
  121. // 参数         : SOCKET socket [in]
  122. // 参数         : char *data [in]
  123. // 参数         : DWORD len  [in]
  124. // 参数         : DWORD *retlen [out]
  125. // 返回值       : bool
  126. //
  127. ///////////////////////////////////////////////////////////////////////
  128. int RecvFix(SOCKET socket, char *data, DWORD len)
  129. {
  130. int retlen = 0;
  131. int nLeft = len;
  132. int nRead = 0;
  133. char *pBuf = data;
  134. while(nLeft > 0)
  135. {
  136.   nRead = recv(socket, pBuf, nLeft, 0);
  137.   if(nRead == SOCKET_ERROR || nRead == 0)
  138.   {
  139.    if(WSAEWOULDBLOCK == WSAGetLastError())
  140.     continue;
  141.    else
  142.     return nRead;
  143.   }
  144.   
  145.   nLeft -= nRead;
  146.   retlen += nRead;
  147.   pBuf += nRead;
  148. }
  149. return nRead;
  150. }


  151. ///////////////////////////////////////////////////////////////////////
  152. //
  153. // 函数名       : SendFix
  154. // 功能描述     : 发送指定长度的数据,考虑非阻塞socket的情况
  155. // 参数         : SOCKET socket
  156. // 参数         : char *data
  157. // 参数         : DWORD len
  158. // 参数         : DWORD *retlen
  159. // 返回值       : bool
  160. //
  161. ///////////////////////////////////////////////////////////////////////
  162. int SendFix(SOCKET socket, char *data, DWORD len)
  163. {
  164. int retlen = 0;
  165. int nLeft = len;
  166. int nWritten = 0;
  167. const char *pBuf = data;
  168. while(nLeft > 0)
  169. {
  170.   nWritten = send(socket, data, nLeft, 0);
  171.   if(nWritten == SOCKET_ERROR || nWritten == 0)
  172.   {
  173.    if(WSAEWOULDBLOCK == WSAGetLastError())
  174.     continue;
  175.    else
  176.     return nWritten;
  177.   }

  178.   
  179.   nLeft -= nWritten;
  180.   retlen += nWritten;
  181.   pBuf += nWritten;
  182. }
  183. return nWritten;
  184. }


  185. /*
  186. ///////////////////////////////////////////////////////////////////////
  187. //
  188. // 函数名       : SelectSend
  189. // 功能描述     : 使用select模型来发送数据,没完成,所以注释掉了
  190. // 参数         : SOCKET sock
  191. // 参数         : FD_SET *wfds
  192. // 参数         : char *data
  193. // 参数         : DWORD len
  194. // 返回值       : bool
  195. //
  196. ///////////////////////////////////////////////////////////////////////
  197. bool SelectSend(SOCKET sock, FD_SET *wfds, char *data, DWORD len)
  198. {
  199. FD_ZERO(wfds);
  200. FD_SET(sock, wfds);

  201. if(select(0, NULL, wfds, NULL, NULL) == SOCKET_ERROR)
  202. {
  203.   OutErr("select() Failed!");
  204.   return false;
  205. }
  206. // 如果是可以写的SOCKET,就一直写,直到返回WSAEWOULDBLOCK
  207. if( FD_ISSET(sock, wfds) )
  208. {
  209.   int nLeft = len;
  210.   while(nLeft > 0)
  211.   {
  212.    int nRet = send(sock, data, len, 0);
  213.    if(nRet == SOCKET_ERROR)
  214.     return false;
  215.    nLeft -= nRet;
  216.   }
  217. }

  218. return true;
  219. }


  220. ///////////////////////////////////////////////////////////////////////
  221. //
  222. // 函数名       : SelectRecv
  223. // 功能描述     : 使用select模型来接收数据,没完成,所以注释掉了
  224. // 参数         : SOCKET sock
  225. // 参数         : FD_SET *rfds
  226. // 参数         : char *data
  227. // 参数         : DWORD len
  228. // 返回值       : bool
  229. //
  230. ///////////////////////////////////////////////////////////////////////
  231. bool SelectRecv(SOCKET sock, FD_SET *rfds, char *data, DWORD len)
  232. {
  233. FD_ZERO(rfds);
  234. FD_SET(sock, rfds);

  235. if(select(0, rfds, NULL, NULL, NULL) == SOCKET_ERROR)
  236. {
  237.   OutErr("select() Failed!");
  238.   return false;
  239. }

  240. if( FD_ISSET(sock, rfds) )
  241. {
  242.   int nLeft = len;
  243.   while(nLeft > 0)
  244.   {
  245.    int nRet = recv(sock, data, len, 0);
  246.    if(nRet == SOCKET_ERROR)
  247.     return false;
  248.    nLeft -= nRet;
  249.   }
  250. }
  251. return true;
  252. }
  253. */


  254. #endif //__COMMONSOCKET_H__
复制代码
/**********************************************************************************************************************/

第四个文件,公用的

/*/
文件: CommonCmd.h
说明:
实现了服务端和客户端一些公用的数据结构,所以服务端和客户端都要包含。
其中有命令、SOCKET的当前状态等的定义。
/*/

  1. #ifndef __COMMONCMD_H__
  2. #define __COMMONCMD_H__

  3. #define PORT 5050

  4. // 命令定义
  5. #define CMD_AUTHEN 1 // 登录认证
  6. #define CMD_GETFILE 2 // 获取文件
  7. #define CMD_REGISTER 3  // 注册用户

  8. typedef struct tagCommand
  9. {
  10. int CommandID;  // 命令ID
  11. DWORD DataSize;  // 后接数据的大小
  12. }SCommand;

  13. // 标志目前的SOCKET该做什么
  14. enum ECurOp
  15. {RecvCmd, RecvData, ExecCmd};


  16. #endif //__COMMONCMD_H__
复制代码
好了,上面四个文件都搞好了,有兴趣的朋友自己去弄吧,希望对你们有用,好累啊(写文章是一件很累的事情)。有什么问题欢迎探讨!
51_avatar_middle
最佳答案
0 
14#
在线会员 发表于 2010-10-9 17:38:29 | 只看该作者
xie xie lou zhu de fengxiang
73_avatar_middle
最佳答案
0 
15#
在线会员 发表于 2010-10-10 19:50:22 | 只看该作者
本帖隐藏的内容需要回复才可以浏览
26_avatar_middle
最佳答案
0 
16#
在线会员 发表于 2010-11-11 11:50:17 | 只看该作者
沙发,支持楼主~~
64_avatar_middle
最佳答案
0 
17#
在线会员 发表于 2010-11-23 12:39:22 | 只看该作者
学习一下WinSocket模型的探讨——select模型,认为这篇文章很不错。因此转载了。
86_avatar_middle
最佳答案
0 
18#
在线会员 发表于 2010-12-3 13:28:52 | 只看该作者
来看下。。。。基础要看好
30_avatar_middle
最佳答案
0 
19#
在线会员 发表于 2010-12-4 00:30:26 | 只看该作者
最近也正在找相关的文章看,来学习一下了,多谢楼主分享
53_avatar_middle
最佳答案
0 
20#
在线会员 发表于 2010-12-4 00:32:35 | 只看该作者
good!!!!!!!!!!!!!!!!!!
您需要登录后才可以回帖 登录 | 加入驿站 qq_login

本版积分规则

×【发帖 友情提示】
1、请回复有意义的内容,请勿恶意灌水;
2、纯数字、字母、表情等无意义的内容系统将自动删除;
3、若正常回复后帖子被自动删除,为系统误删的情况,请重新回复其他正常内容或等待管理员审核通过后会自动发布;
4、感谢您对VC驿站一如既往的支持,谢谢合作!

关闭

站长提醒上一条 /2 下一条

|小黑屋|手机版|VC驿站 ( )|网站地图QQ

GMT+8, 2020-8-25 07:30

Powered by vog2jy.com

© 2009-2020 vog2jy.com

快速回复 返回顶部 返回列表