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

参见:MFC中Socket网络通讯

 

posted @   htj10  阅读(379)  评论(0编辑  收藏  举报
编辑推荐:
· .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 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
TOP
点击右上角即可分享
微信分享提示