当前位置:   article > 正文

Windows上的Socket编程(阻塞模型)_windows+sockets网络开发

windows+sockets网络开发

Socket协议的工作原理

Socket又称套接字,它是TCP/IP网络环境下应用程序与底层通信驱动程序之间运行的开发接口,它可以将应用程序与具体的TCP/IP隔离开,使得应用程序不需要了解TCP/IP的细节,就能够实现传输。

TCP协议使用的send、recv、WSASend和WSARecv,
UDP协议使用的sendto、recvfrom、WSASendTo 和WSARecvFrom。

什么是WSASend?
作用:在一个已连接的套接口上发送数据。

需要包括的库

  1. #include <WinSock2.h>
  2. #pragma comment(lib,"Ws2_32.lib ")

用到的函数

1. WSAStartup   初始化Ws2_32.dll的函数

  1. int WSAStartup(
  2. __in WORD wVersionRequested,
  3. __out LPWSADATA lpWSAData
  4. );

wVersionRequested

标识了用户调用的Winsock的版本号。高字节指明辅版本编号,低字节指明主版本编号。通常使用MAKEWORD来生成一个版本号。 当前Winsock sockets的版本号为2.2,用到的dll是 Ws2_32.dll。

lpWSAData

指向WSADATA结构体的指针,lpWSAData返回了系统对Windows Sockets 的描述

Return Value

如果调用成功,WSAStartup 函数返回0。否则,将返回五种错误代码之一

2. WSACleanup   释放Ws2_32.dl的l函数

int WSACleanup(void);

返回值0表示正常退出,返回值SOCKET_ERROR表示异常。返回值是SOCKET_ERROR,可以调用 WSAGetLastError.查看错误代码。需要注意的是,在多线程环境下,WSACleanup 函数将终止所有线程的socket操作。

3. socket   创建socket的函数

  1. SOCKET WSAAPI socket(
  2. __in int af,
  3. __in int type,
  4. __in int protocol
  5. );
  6. af   ( address family)
  7.   指明地址簇类型,常用的地址簇如下,其余地址簇在Winsock2.h中定义。
  8. AF_UNSPEC(未指明)、
  9. AF_INET(IPv4)、
  10. AF_NETBIOS(NETBIOS地址簇)、
  11. AF_INET6(IPv6)、
  12. AF_IRDA(Infrared Data Association (IrDA)地址簇)、
  13. AF_BTM(Bluetooth)。
  14. type
  15.   指明socket的类型,Windows Sockets 2常见类型如下:
  16. SOCK_STREAM(流套接字,使用TCP协议)、
  17. SOCK_DGRAM(数据报套接字,使用UDP协议)、
  18. SOCK_RAW(原始套接字)、
  19. SOCK_RDM(提供可靠的消息数据报文,reliable message datagram)、
  20. SOCK_SEQPACKET(Provides a pseudo-stream packet based on datagrams,在UDP的基础上提供了伪流数据包)。
  21. protocol
  22. 指明数据传输协议,该参数取决于af和type参数的类型。protocol参数在Winsock2.h and Wsrm.h定义。通常使用如下3中协议:
  23. IPPROTO_TCP(TCP协议,使用条件,af是AF_INET or AF_INET6type是SOCK_STREAM )
  24. IPPROTO_UDP(UDP协议,使用条件,af是AF_INET or AF_INET6type是SOCK_DGRAM)
  25. IPPROTO_RM(PGM(Pragmatic General Multicast,实际通用组播协议)协议,使用条件,af是AF_INET 、type是SOCK_RDM)

4. bind    服务端将socket与地址关联

5. listen    服务端网络监听

6. accept   服务端connect接收

7. connect   客户端请求服务端连接

8. send   发送数据

TCP连接流程

TCP服务端代码

  1. // WinServer.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
  2. //
  3. #include "pch.h"
  4. #include <iostream>
  5. #include <WinSock2.h>
  6. #pragma comment(lib, "ws2_32.lib")
  7. int main()
  8. {
  9. WORD wVersion = MAKEWORD(2, 2);
  10. WSADATA wsaData = { 0 };
  11. //WinSocket初始化
  12. if (WSAStartup(wVersion, &wsaData))
  13. {
  14. std::cout << "WSAStartup Error" << std::endl;
  15. return 1;
  16. }
  17. //创建socket
  18. SOCKET nServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  19. if (nServerSocket == INVALID_SOCKET)
  20. {
  21. std::cout << "create socket Error" << std::endl;
  22. WSACleanup();//释放WinSocket
  23. return 1;
  24. }
  25. sockaddr_in serverAddr = { 0 };
  26. serverAddr.sin_family = AF_INET;
  27. serverAddr.sin_port = htons(8888); //绑定端口
  28. serverAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //绑定ip
  29. //绑定ip和端口
  30. if (SOCKET_ERROR == bind(nServerSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)))
  31. {
  32. std::cout << "bind Error" << std::endl;
  33. closesocket(nServerSocket);
  34. WSACleanup();//释放WinSocket
  35. return 1;
  36. }
  37. //监听 最大连接数为5
  38. if (SOCKET_ERROR == listen(nServerSocket, 5))
  39. {
  40. std::cout << "listen Error" << std::endl;
  41. closesocket(nServerSocket);
  42. WSACleanup();//释放WinSocket
  43. return 1;
  44. }
  45. SOCKET nClientSocket = { 0 };
  46. sockaddr_in clientAddr = { 0 };
  47. int nLen = sizeof(clientAddr);
  48. //接受客户端连接请求
  49. nClientSocket = accept(nServerSocket, (sockaddr*)&clientAddr, &nLen);
  50. if (INVALID_SOCKET == nClientSocket)
  51. {
  52. std::cout << "accept Error" << std::endl;
  53. closesocket(nServerSocket);
  54. WSACleanup();//释放WinSocket
  55. }
  56. char szBuffer[255] = { 0 };
  57. int nRet = 0;
  58. //接收客户端数据
  59. while (true)
  60. {
  61. memset(szBuffer, 0, 255);
  62. //接受客户端发来的数据
  63. nRet = recv(nClientSocket, szBuffer, 255, 0);
  64. if (nRet == SOCKET_ERROR)
  65. {
  66. std::cout << "recv Error" << std::endl;
  67. closesocket(nClientSocket);
  68. closesocket(nServerSocket);
  69. WSACleanup();//释放WinSocket
  70. return 1;
  71. }
  72. std::cout << szBuffer << std::endl;
  73. nRet = send(nClientSocket, szBuffer, 255, 0);
  74. if (nRet == SOCKET_ERROR)
  75. {
  76. std::cout << "send Error" << std::endl;
  77. closesocket(nClientSocket);
  78. closesocket(nServerSocket);
  79. WSACleanup();//释放WinSocket
  80. return 1;
  81. }
  82. }
  83. closesocket(nClientSocket);
  84. closesocket(nServerSocket);
  85. WSACleanup();//释放WinSocket
  86. return 0;
  87. }

TCP客户端代码

  1. // WinClient.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
  2. //
  3. #include "pch.h"
  4. #include <iostream>
  5. #include <WS2tcpip.h>
  6. #include <WinSock2.h>
  7. #pragma comment(lib, "ws2_32.lib")
  8. int main()
  9. {
  10. WSADATA wsaData = { 0 };
  11. SOCKET nClientSocket = { 0 };
  12. int nRet = 0;
  13. char szBuffer[255];
  14. //WinSocket初始化
  15. if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
  16. {
  17. std::cout << "WSAStartup failed!\n";
  18. return 1;
  19. }
  20. //创建socket
  21. nClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  22. if (nClientSocket == INVALID_SOCKET)
  23. {
  24. std::cout << "socket failed!\n";
  25. //释放
  26. WSACleanup();
  27. return 1;
  28. }
  29. SOCKADDR_IN addrServ = { 0 };
  30. addrServ.sin_family = AF_INET;
  31. addrServ.sin_port = htons(8888); //绑定端口
  32. inet_pton(AF_INET, "127.0.0.1", &addrServ.sin_addr); //服务器ip
  33. //连接服务器
  34. nRet = connect(nClientSocket, (LPSOCKADDR)&addrServ, sizeof(SOCKADDR_IN));
  35. if (nRet == SOCKET_ERROR)
  36. {
  37. std::cout << "connect failed!\n";
  38. closesocket(nClientSocket);
  39. WSACleanup();
  40. return 1;
  41. }
  42. while (true)
  43. {
  44. memset(szBuffer, 0, 255);
  45. std::cout << "Please input a string:";
  46. std::cin >> szBuffer;
  47. //发送数据
  48. nRet = send(nClientSocket, szBuffer, strlen(szBuffer), 0);
  49. if (nRet == SOCKET_ERROR)
  50. {
  51. std::cout << "send failed!\n";
  52. closesocket(nClientSocket);
  53. WSACleanup();
  54. return -1;
  55. }
  56. memset(szBuffer, 0, sizeof(szBuffer));
  57. //接收数据
  58. nRet = recv(nClientSocket, szBuffer, sizeof(szBuffer), 0);
  59. if (nRet == SOCKET_ERROR)
  60. {
  61. std::cout << "recv failed!\n";
  62. closesocket(nClientSocket);
  63. WSACleanup();
  64. return 1;
  65. }
  66. std::cout << szBuffer << std::endl;
  67. }
  68. closesocket(nClientSocket);
  69. WSACleanup();
  70. return 0;
  71. }

UDP

sendto

  1. int sendto(
  2.   __in  SOCKET s, //指定套接字(可能已连接)
  3.   __in  const char *buf, //指向将要发送数据的缓冲区
  4.   __in  int len, //缓冲区大小
  5.   __in  int flags, //指定数据传输方式
  6.   __in  const struct sockaddr *to, //可选的指针,指向存储目标套接字地址信息的sockaddr结构
  7.   __in  int tolen //to参数指向结构的字节大小
  8. );
  9. 返回值:
  10. 成功时,返回发送的字节数;
  11. 失败时,返回SOCKET_ERROR,调用WSAGetLastError函数查看进一步错误信息。

 recvfrom

  1. recvfrom函数用于接收数据报并存储发送方源地址信息:
  2. int recvfrom(
  3.   __in         SOCKET s, //指定一个绑定的socket
  4.   __out        char *buf, //存放接到的数据的缓冲区
  5.   __in         int len, //缓冲区字节大小
  6.   __in         int flags, //指定传输控制方式
  7.   __out        struct sockaddr *from, //可选的指针,函数成功返回后,
  8. //指向存储源套接字地址信息的sockaddr结构
  9.   __inout_opt  int *fromlen //from的字节大小
  10. );
  11. 返回值:
  12. 成功时,返回接收的字节数;
  13. 失败时,返回SOCKET_ERROR,调用WSAGetLastError函数查看进一步错误信息。

UDP服务端

  1. // WinServer.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
  2. //
  3. #include "pch.h"
  4. #include <iostream>
  5. #include <WinSock2.h>
  6. #pragma comment(lib, "ws2_32.lib")
  7. int main()
  8. {
  9. WORD wVersion = MAKEWORD(2, 2);
  10. WSADATA wsaData = { 0 };
  11. //WinSocket初始化
  12. if (WSAStartup(wVersion, &wsaData))
  13. {
  14. std::cout << "WSAStartup Error" << std::endl;
  15. return 1;
  16. }
  17. //创建socket
  18. SOCKET nServerSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  19. if (nServerSocket == INVALID_SOCKET)
  20. {
  21. std::cout << "create socket Error" << std::endl;
  22. WSACleanup();//释放WinSocket
  23. return 1;
  24. }
  25. sockaddr_in serverAddr = { 0 };
  26. serverAddr.sin_family = AF_INET;
  27. serverAddr.sin_port = htons(8888); //绑定端口
  28. serverAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //绑定ip
  29. //绑定ip和端口
  30. if (SOCKET_ERROR == bind(nServerSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)))
  31. {
  32. std::cout << "bind Error" << std::endl;
  33. closesocket(nServerSocket);
  34. WSACleanup();//释放WinSocket
  35. return 1;
  36. }
  37. sockaddr clientAddr = { 0 };
  38. int nLen = sizeof(clientAddr);
  39. char szBuffer[255] = { 0 };
  40. int nRet = recvfrom(nServerSocket, szBuffer, 255, 0, &clientAddr, &nLen);
  41. if (nRet)
  42. {
  43. std::cout << szBuffer << std::endl;
  44. }
  45. closesocket(nServerSocket);
  46. WSACleanup();//释放WinSocket
  47. getchar();
  48. return 0;
  49. }

UDP客户端

  1. // WinClient.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
  2. //
  3. #include "pch.h"
  4. #include <iostream>
  5. #include <WS2tcpip.h>
  6. #include <WinSock2.h>
  7. #pragma comment(lib, "ws2_32.lib")
  8. int main()
  9. {
  10. WSADATA wsaData = { 0 };
  11. SOCKET nClientSocket = { 0 };
  12. //WinSocket初始化
  13. if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
  14. {
  15. std::cout << "WSAStartup failed!\n";
  16. return 1;
  17. }
  18. //创建socket
  19. nClientSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  20. if (nClientSocket == INVALID_SOCKET)
  21. {
  22. std::cout << "socket failed!\n";
  23. //释放
  24. WSACleanup();
  25. return 1;
  26. }
  27. sockaddr_in addrServ = { 0 };
  28. addrServ.sin_family = AF_INET;
  29. addrServ.sin_port = htons(8888); //服务器端口
  30. inet_pton(AF_INET, "127.0.0.1", &addrServ.sin_addr); //服务器ip
  31. char szBuffer[255] = "123456";
  32. int nRet = sendto(nClientSocket, szBuffer, 255, 0, (sockaddr*)&addrServ, sizeof(addrServ));
  33. if (nRet)
  34. {
  35. std::cout << "send success" << std::endl;
  36. }
  37. closesocket(nClientSocket);
  38. WSACleanup();
  39. getchar();
  40. return 0;
  41. }

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号