当前位置:   article > 正文

TCP Socket通信学习

TCP Socket通信学习

学习内容,参见《Windows网络编程》 第7章 Winsock基础

服务器/客户端连接模型见下图。


服务端流程

  • 用socket或WSASocket创建一个套接字。
  • 用bind绑定套接字到本地IP地址(多网卡时,本地有多个IP)。
  • 用listen将套接字置为监听模式。
  • 通过accept或WSAAccept来接受客户连接。
  • 用send或WSASend发送信息,用recv或WSARecv接受信息。

客户端流程

  • 用socket或WSASocket创建一个套接字。
  • 解析服务器名。
  • 用connect或WSAConnect初始化一个连接。
  • 用send或WSASend发送信息,用recv或WSARecv接受信息。

使用windows的Winsock 2编程,创建win32控制台工程,进行工程配置。

  • 工程右键Properties->Configuration Properties->Linker->Input->Additional Dependencies中添加ws2_32.lib。
  • Demo代码采用Multi-Byte方式,设置Properties->Configuration Properties->General->Character Set为Use Multi-Byte Character Set。

服务端代码,TCPServer.cpp。

  1. // TCPServer.cpp : Defines the entry point for the console application.
  2. //
  3. #include "stdafx.h"
  4. #include <WinSock2.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #define DEFAULT_PORT 5150
  8. #define DEFAULT_BUFFER 4096
  9. int iPort = DEFAULT_PORT;//Port to listen for clients on
  10. BOOL bInterface = FALSE;//Listen on the specified interface
  11. BOOL bRecvOnly = FALSE;//Receive data only; don't echo back
  12. TCHAR szAddress[128];//Interface to listen for clients on
  13. //Print usage information and exit
  14. void usage()
  15. {
  16. printf("usage:server[-p:x][-i:IP][-o]\n\n");
  17. printf(" -p:x Port number to listen on\n");
  18. printf(" -i:str Interface to listen on\n");
  19. printf(" -o Don't echo the data back\n\n");
  20. ExitProcess(1);
  21. }
  22. //Parse the command line arguments, and set some global flags
  23. //to indicate what actions to perform
  24. void ValidateArgs(int agrc, _TCHAR** argv)
  25. {
  26. for (int i = 1; i < agrc; i++)
  27. {
  28. if ((argv[i][0] == _T('-')) || (argv[i][0] == _T('/')))
  29. {
  30. switch (tolower(argv[i][1]))
  31. {
  32. case _T('p'):
  33. iPort = _ttoi(&argv[i][3]);
  34. break;
  35. case _T('i'):
  36. bInterface = TRUE;
  37. if (_tcslen(argv[i]) > 3)
  38. {
  39. _tcscpy_s(szAddress, &argv[i][3]);
  40. }
  41. break;
  42. case _T('o'):
  43. //只接受数据
  44. bRecvOnly = TRUE;
  45. break;
  46. default:
  47. usage();
  48. break;
  49. }
  50. }
  51. }
  52. }
  53. DWORD WINAPI ClientThread(LPVOID lpParam)
  54. {
  55. SOCKET sock = (SOCKET)lpParam;
  56. char szBuff[DEFAULT_BUFFER];
  57. while (true)
  58. {
  59. //Perform a blocking recv() call
  60. int ret = recv(sock, szBuff, DEFAULT_BUFFER, 0);
  61. if (0 == ret)
  62. {
  63. break;
  64. }
  65. else if (SOCKET_ERROR == ret)
  66. {
  67. printf("recv() failed:%d\n", WSAGetLastError());
  68. break;
  69. }
  70. szBuff[ret] = '\0';
  71. printf("RECV:'%s'\n", szBuff);
  72. //if we selected to echo the data back, do it
  73. if (!bRecvOnly)
  74. {
  75. int nLeft = ret;
  76. int idx = 0;
  77. //make sure we write all the data
  78. while (nLeft > 0)
  79. {
  80. ret = send(sock, &szBuff[idx], nLeft, 0);
  81. if (0 == ret)
  82. {
  83. break;
  84. }
  85. else if (SOCKET_ERROR == ret)
  86. {
  87. printf("send() failed:%d\n", WSAGetLastError());
  88. break;
  89. }
  90. nLeft -= ret;
  91. idx += ret;
  92. }
  93. }
  94. }
  95. return 0;
  96. }
  97. int _tmain(int argc, _TCHAR* argv[])
  98. {
  99. ValidateArgs(argc, argv);
  100. WSADATA wsd;
  101. if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
  102. {
  103. printf("Failed to load Winsock!\n");
  104. return 1;
  105. }
  106. //Create our listening socket
  107. SOCKET sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
  108. if (sListen == SOCKET_ERROR)
  109. {
  110. printf("socket() failed:%d\n", WSAGetLastError());
  111. return 1;
  112. }
  113. //Select the local interface, and bind to it
  114. struct sockaddr_in local;
  115. if (bInterface)
  116. {
  117. local.sin_addr.s_addr = inet_addr(szAddress);
  118. if (local.sin_addr.s_addr == INADDR_NONE)
  119. {
  120. usage();
  121. }
  122. }
  123. else
  124. {
  125. //INADDR_ANY是所有网卡地址
  126. local.sin_addr.s_addr = htonl(INADDR_ANY);
  127. }
  128. local.sin_family = AF_INET;
  129. local.sin_port = htons(iPort);
  130. //绑定监听网卡地址和端口
  131. if (bind(sListen, (struct sockaddr*)&local, sizeof(local)) == SOCKET_ERROR)
  132. {
  133. printf("bind() failed:%d\n", WSAGetLastError());
  134. }
  135. //开始监听客户端
  136. listen(sListen, 8);
  137. printf("begin accept on port:%d\n", iPort);
  138. //In a continuous loop, wait for incoming clients.Once one
  139. //is detected, create a thread and pass the handle off to it
  140. while (true)
  141. {
  142. struct sockaddr_in client;
  143. int iAddrSize = sizeof(client);
  144. SOCKET sClient = accept(sListen, (struct sockaddr*)&client, &iAddrSize);
  145. if (sClient == INVALID_SOCKET)
  146. {
  147. printf("accept() failed:%d\n", WSAGetLastError());
  148. break;
  149. }
  150. printf("Accepted client:%s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
  151. DWORD dwThreadId;
  152. HANDLE hThread = CreateThread(NULL, 0, ClientThread, (LPVOID)sClient,
  153. 0, &dwThreadId);
  154. if (hThread == NULL)
  155. {
  156. printf("CreateThread() failed:%d\n", GetLastError());
  157. break;
  158. }
  159. CloseHandle(hThread);
  160. }
  161. closesocket(sListen);
  162. WSACleanup();
  163. return 0;
  164. }

 

客户端代码,TCPClient.cpp。

  1. // TCPClient.cpp : Defines the entry point for the console application.
  2. //
  3. #include "stdafx.h"
  4. #include <WinSock2.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #define DEFAULT_COUNT 5
  8. #define DEFAULT_PORT 5150
  9. #define DEFAULT_BUFFER 2048
  10. #define DEFAULT_MESSAGE _T("This is a test of the emergency broadcasting system")
  11. TCHAR szServer[128];
  12. TCHAR szMessage[1024];
  13. int iPort = DEFAULT_PORT;
  14. DWORD dwCount = DEFAULT_COUNT;
  15. BOOL bSendOnly = FALSE;
  16. //Print usage information and exit
  17. void usage()
  18. {
  19. printf("usage:client[-p:x][-s:IP][-n:x][-o]\n\n");
  20. printf(" -p:x Remote port to send to \n");
  21. printf(" -s:IP Server's IP address or host name\n");
  22. printf(" -n:x Number of times to send message\n");
  23. printf(" -o Send messages only; don't receive\n");
  24. ExitProcess(1);
  25. }
  26. //Parse the command line arguments, and set some global flags
  27. //to indicate what actions to perform
  28. void ValidateArgs(int argc, _TCHAR** argv)
  29. {
  30. for (int i = 1; i < argc; i++)
  31. {
  32. if ((argv[i][0] == _T('-')) || (argv[i][0] == _T('/')))
  33. {
  34. switch (tolower(argv[i][1]))
  35. {
  36. case _T('p'):
  37. if (_tcslen(argv[i]) > 3)
  38. {
  39. iPort = _ttoi(&argv[i][3]);
  40. }
  41. break;
  42. case _T('s'):
  43. if (_tcslen(argv[i]) > 3)
  44. {
  45. _tcscpy_s(szServer, &argv[i][3]);
  46. }
  47. break;
  48. case _T('n'):
  49. if (_tcslen(argv[i]) > 3)
  50. {
  51. dwCount = _ttol(&argv[i][3]);
  52. }
  53. break;
  54. case _T('o'):
  55. bSendOnly = TRUE;
  56. break;
  57. default:
  58. usage();
  59. break;
  60. }
  61. }
  62. }
  63. }
  64. int _tmain(int argc, _TCHAR* argv[])
  65. {
  66. ValidateArgs(argc, argv);
  67. WSADATA wsd;
  68. if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
  69. {
  70. printf("Failed to load Winsock library!\n");
  71. return 1;
  72. }
  73. _tcscpy_s(szMessage, DEFAULT_MESSAGE);
  74. //Create the socket, and attempt to connect to the server
  75. SOCKET sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
  76. if (sClient == INVALID_SOCKET)
  77. {
  78. printf("socket() failed:%d\n", WSAGetLastError());
  79. return 1;
  80. }
  81. struct sockaddr_in server;
  82. server.sin_family = AF_INET;
  83. server.sin_port = htons(iPort);
  84. //If the supplied server address wasn't in the form
  85. //"aaa.bbb.ccc.ddd,"it's a host name, so try to resolve it
  86. int nServerLen = (int)_tcslen(szServer);
  87. if (0 == nServerLen)
  88. {
  89. struct hostent* host = gethostbyname(szServer);
  90. if (host == NULL)
  91. {
  92. printf("Unable to resolve server:%s\n", szServer);
  93. return 1;
  94. }
  95. CopyMemory(&server.sin_addr, host->h_addr_list[0], host->h_length);
  96. }
  97. else
  98. {
  99. server.sin_addr.s_addr = inet_addr(szServer);
  100. }
  101. if (connect(sClient, (struct sockaddr*)&server, sizeof(server))
  102. == SOCKET_ERROR)
  103. {
  104. printf("connect() failed:%d\n", WSAGetLastError());
  105. return 1;
  106. }
  107. //Send and receive data
  108. char szBuffer[DEFAULT_BUFFER];
  109. int ret = 0;
  110. for (int i = 0; i < (int)dwCount; i++)
  111. {
  112. ret = send(sClient, szMessage, (int)_tcslen(szMessage), 0);
  113. if (ret == 0)
  114. {
  115. break;
  116. }
  117. else if (ret == SOCKET_ERROR)
  118. {
  119. printf("send() failed:%d\n", WSAGetLastError());
  120. break;
  121. }
  122. printf("Send %d bytes\n", ret);
  123. if (!bSendOnly)
  124. {
  125. ret = recv(sClient, szBuffer, DEFAULT_BUFFER, 0);
  126. if (ret == 0)
  127. {
  128. break;
  129. }
  130. else if (ret == SOCKET_ERROR)
  131. {
  132. printf("recv() failed:%d\n", WSAGetLastError());
  133. break;
  134. }
  135. szBuffer[ret] = _T('\0');
  136. printf("RECV [%d bytes]:'%s'\n", ret, szBuffer);
  137. }
  138. }
  139. closesocket(sClient);
  140. WSACleanup();
  141. return 0;
  142. }

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号