Windows下socket编程(console非MFC)
console控制台:使用<winsock2.h> 和 ws2_32.lib 参考:孙鑫C++课程14
TCP:面对连接的、安全的通信
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | ////// TcpSrv.cpp ///////// #define _CRT_SECURE_NO_WARNINGS //用sprintf,而不必强制使用sprintf_s 不报错 #include <winsock2.h> #include <iostream> using namespace std; #pragma comment(lib,"ws2_32.lib") void main() { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(1, 1); //WSAStartup() initiates use of Ws2_32.dll by a process. err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { return ; } if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup(); return ; } //1.创建流式套接字,基于TCP(SOCK_STREAM) SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0); //socket地址结构体 SOCKADDR_IN addrSrv; //除了sin_family,其余都需要转换为网络字节序 addrSrv.sin_family = AF_INET; addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //转换Unsigned long型为网络字节序格式, INADDR_ANY表示接受多个IP地址的回应信息 addrSrv.sin_port = htons(6000); //端口6000,转换unsigned short为网络字节序 //2.将套接字绑定到一个端口号和本地地址上 bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof (SOCKADDR)); //3.监听 listen(sockSrv, 5); // SOCKADDR_IN addrClient; //定义用来接收客户端Socket的结构体 int len = sizeof (SOCKADDR); //初始化参数,这个参数必须进行初始化 //4.循环等待接受客户端发送请求 while ( true ) { //等待客户请求到来;当请求到来后,接受连接请求, //返回一个新的对应于此次连接的套接字(sockConnect)。 //接受Client请求,阻塞 SOCKET sockConnect = accept(sockSrv, (SOCKADDR*)&addrClient, &len); //发送数据 char buf[100]; //inet_ntoa(addrClient.sin_addr)将IP地址转换为字符串,像 "192.168.0.5" sprintf (buf, "Welcome %s to my little world." , inet_ntoa(addrClient.sin_addr)); send(sockConnect, buf, strlen (buf) + 1, 0); //多发一个,为了\0结尾 //接收数据 char recvBuf[100] = { 0 }; recv(sockConnect, recvBuf, sizeof (recvBuf), 0); cout << recvBuf << endl; //5.关闭socket closesocket(sockConnect); } // WSACleanup(); return ; } ////////////////////////////////////////////////////////// ///////// TcpClient.cpp //////////// #define _CRT_SECURE_NO_WARNINGS //用sprintf,而不必强制使用sprintf_s 不报错 #include <winsock2.h> #include <iostream> using namespace std; #pragma comment(lib,"ws2_32.lib") void main() { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(1, 1); //WSAStartup() initiates use of Ws2_32.dll by a process. err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { return ; } if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup(); return ; } //1.创建Client端的Socket SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0); //2.连接Server地址 SOCKADDR_IN addrSrv; addrSrv.sin_family = AF_INET; addrSrv.sin_addr.S_un.S_addr = inet_addr( "127.0.0.1" ); //inet_addr 将IP字符串转为ULONG类型数值 addrSrv.sin_port = htons(6000); //Port:6000 connect(sockClient, (SOCKADDR*)&addrSrv, sizeof (SOCKADDR)); //接收 char recvBuf[100] = { 0 }; recv(sockClient, recvBuf, sizeof (recvBuf), 0); cout << recvBuf << endl; //发送 char * buf = "This is lisi." ; send(sockClient, buf, strlen (buf) + 1, 0); //3.关闭套接字 closesocket(sockClient); WSACleanup(); //终止套接字库的使用 } |
总结:
TCP服务端
1. 创建流套接字(SOCK_STREAM)sockSrv
2. 绑定本地IP地址和端口 bind(...)
3. 监听 listen(...)
4. 等待Client端连接 accept(...) 此函数获得Client端的SOCKADDR(包括IP地址,端口等)
5. 发送数据或接收数据 send( ) / recv( )
6. 关闭套接字
TCP客户端
1. 创建流套接字
2. 连接Server端,connect( )
3. 发送或接收数据 send recv
4. 关闭套接字
UDP服务器端
1. 创建数据报套接字(SOCK_DGRAM)sockSrv
2. bind 本地的IP地址 SOCKADDR(实际用 SOCKADDR_IN)
3. 接收数据 recvfrom(..) 此函数保存CLient端的 SOCKADDR(IP地址等) 发送数据 sendto()
4. 关闭套接字
UDP客户端
1. 创建数据报套接字(SOCK_DGRAM)sockClient
2. 给Server端发送数据 sendto() 接收数据 recvfrom( )
3. 关闭套接字
UDP:面向无连接,不安全的,即时通信
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | ////// UdpSrv.cpp ///////// #define _CRT_SECURE_NO_WARNINGS //用sprintf,而不必强制使用sprintf_s 不报错 #include <winsock2.h> #include <iostream> using namespace std; #pragma comment(lib,"ws2_32.lib") void main() { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(1, 1); //WSAStartup() initiates use of Ws2_32.dll by a process. err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { return ; } if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup(); return ; } //1.创建数据报套接字,基于UDP(SOCK_DGRAM) SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0); //socket地址结构体 SOCKADDR_IN addrSrv; //除了sin_family,其余都需要转换为网络字节序 addrSrv.sin_family = AF_INET; addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //转换Unsigned long型为网络字节序格式, INADDR_ANY表示接受多个IP地址的回应信息 addrSrv.sin_port = htons(6000); //端口6000,转换unsigned short为网络字节序 //2.将套接字绑定到一个端口号和本地地址上 bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof (SOCKADDR)); // SOCKADDR_IN addrClient; //定义用来接收客户端Socket的结构体 int len = sizeof (SOCKADDR); //初始化参数,这个参数必须进行初始化 //接收数据 recvfrom 将Client端的IP地址,端口号等存到addrClient char recvBuf[100] = { 0 }; recvfrom(sockSrv, recvBuf, sizeof (recvBuf), 0,(SOCKADDR*)&addrClient,&len); //阻塞 cout << inet_ntoa(addrClient.sin_addr) //inet_ntoa(addrClient.sin_addr)将IP地址转换为字符串,像 "192.168.0.5" << " say: " << recvBuf << endl; //发送数据 sendto cout << "Please input something for sending: " ; char sendBuf[100]; gets (sendBuf); //从屏幕获取一行字符串存到sendBuf中 sendto(sockSrv, sendBuf, strlen (sendBuf) + 1, 0, (SOCKADDR*)&addrClient, len); //多发一个,为了\0结尾 //3.关闭socket closesocket(sockSrv); WSACleanup(); system ( "pause" ); return ; } /////////////////////////////////////////////////////////// ////// UdpClient.cpp ///////// #define _CRT_SECURE_NO_WARNINGS //用sprintf,而不必强制使用sprintf_s 不报错 #include <winsock2.h> #include <iostream> using namespace std; #pragma comment(lib,"ws2_32.lib") void main() { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(1, 1); //WSAStartup() initiates use of Ws2_32.dll by a process. err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { return ; } if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup(); return ; } //1.创建套接字 SOCKET sockClient = socket(AF_INET, SOCK_DGRAM, 0); //发送 SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = inet_addr( "127.0.0.1" ); addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(6000); cout << "Please input something for sending: " ; char sendBuf[100]; gets (sendBuf); sendto(sockClient, sendBuf, strlen (sendBuf), 0, (SOCKADDR*)&addrSrv, sizeof (SOCKADDR)); //接收数据 recvfrom char recvBuf[100] = { 0 }; int len = sizeof (SOCKADDR); recvfrom(sockClient, recvBuf, sizeof (recvBuf), 0, (SOCKADDR*)&addrSrv, &len); //阻塞 cout << inet_ntoa(addrSrv.sin_addr) //inet_ntoa(addrClient.sin_addr)将IP地址转换为字符串,像 "192.168.0.5" << " say: " << recvBuf << endl; //2.关闭套接字 closesocket(sockClient); WSACleanup(); system ( "pause" ); } /////////////////////////////////////////////////////////////// |
MFC的Socket通信:使用#include <afxsock.h>中MFC封装的类CSocket
常记溪亭日暮,沉醉不知归路。兴尽晚回舟,误入藕花深处。争渡,争渡,惊起一滩鸥鹭。
昨夜雨疏风骤,浓睡不消残酒。试问卷帘人,却道海棠依旧。知否?知否?应是绿肥红瘦。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义