服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C++ Socket实现TCP与UDP网络编程

C++ Socket实现TCP与UDP网络编程

2022-08-31 16:14cpp_learners C/C++

本文主要介绍了C++ Socket实现TCP与UDP网络编程,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

前言

socket编程分为TCP和UDP两个模块,其中TCP是可靠的、安全的,常用于发送文件等,而UDP是不可靠的、不安全的,常用作视频通话等。

如下图:

C++ Socket实现TCP与UDP网络编程

头文件与库:

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

准备工作:

创建工程后,首先右键工程,选择属性

C++ Socket实现TCP与UDP网络编程

然后选择 C/C++ - 预处理器 - 预处理器定义

C++ Socket实现TCP与UDP网络编程

将字符串 _WINSOCK_DEPRECATED_NO_WARNINGS 添加到里面去,点击应用即可!

TCP

连接过程图:

C++ Socket实现TCP与UDP网络编程

创建tcp服务器和客户端都是按照上图的步骤来操作的!

1). 服务器

初始化套接字库
对应图中socket()

?
1
2
3
4
5
6
7
8
9
WORD wVersion;
WSADATA wsaData;
int err;
 
// 设置版本,可以理解为1.1
wVersion = MAKEWORD(1, 1);  // 例:MAKEWORD(a, b) --> b | a << 8 将a左移8位变成高位与b合并起来
 
// 启动
err = WSAStartup(wVersion, &wsaData);

创建tcp套接字
对应图中socket()

?
1
2
// AF_INET:ipv4   AF_INET6:ipv6
SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);

绑定到本机
对应图中bind()

?
1
2
3
4
5
6
7
8
9
// 准备绑定信息
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);   // 设置绑定网卡
addrSrv.sin_family = AF_INET;       // 设置绑定网络模式
addrSrv.sin_port = htons(6000);     // 设置绑定端口
// hton: host to network  x86:小端    网络传输:htons大端
 
// 绑定到本机
int retVal = bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));

监听
对应图中listen()

?
1
2
// 同时能接收10个链接,主要看参数二的设置个数
listen(sockSrv, 10);

接收连接请求,返回针对客户端的套接字
对应图中accept()

?
1
SOCKET sockConn = accept(sockSrv, (SOCKADDR *)&addrCli, &len);

发送数据
对应图中write()

?
1
2
sprintf_s(sendBuf, "hello client!\n");
int iSend = send(sockConn, sendBuf, strlen(sendBuf) + 1, 0);

接收数据
对应图中read()

?
1
recv(sockConn, recvBuf, 100, 0);

关闭套接字
对应图中close()

?
1
closesocket(sockConn);

清理套接字库

?
1
WSACleanup();

具体实现代码

?
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
#include <iostream>
#include <stdio.h>
#include <WinSock2.h>
 
#pragma comment(lib, "ws2_32.lib")
 
 
int main(void) {
 
    // 1.初始化套接字库
    WORD wVersion;
    WSADATA wsaData;
    int err;
 
    // 设置版本,可以理解为1.1
    wVersion = MAKEWORD(1, 1);  // 例:MAKEWORD(a, b) --> b | a << 8 将a左移8位变成高位与b合并起来
 
    // 启动
    err = WSAStartup(wVersion, &wsaData);
    if (err != 0) {
        return err;
    }
    // 检查:网络低位不等于1 || 网络高位不等于1
    if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {
        // 清理套接字库
        WSACleanup();
        return -1;
    }
 
    // 2.创建tcp套接字       // AF_INET:ipv4   AF_INET6:ipv6
    SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);
 
    // 准备绑定信息
    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);   // 设置绑定网卡
    addrSrv.sin_family = AF_INET;       // 设置绑定网络模式
    addrSrv.sin_port = htons(6000);     // 设置绑定端口
    // hton: host to network  x86:小端    网络传输:htons大端
 
    // 3.绑定到本机
    int retVal = bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));
    if (retVal == SOCKET_ERROR) {
        printf("Failed bind:%d\n", WSAGetLastError());
        return -1;
    }
 
    // 4.监听,同时能接收10个链接
    if (listen(sockSrv, 10) == SOCKET_ERROR) {
        printf("Listen failed:%d", WSAGetLastError());
        return -1;
    }
 
    std::cout << "Server start at port: 6000" << std::endl;
 
    SOCKADDR_IN addrCli;
    int len = sizeof(SOCKADDR);
 
    char recvBuf[100];
    char sendBuf[100];
    while (1) {
        // 5.接收连接请求,返回针对客户端的套接字
        SOCKET sockConn = accept(sockSrv, (SOCKADDR *)&addrCli, &len);
        if (sockConn == SOCKET_ERROR) {
            //printf("Accept failed:%d", WSAGetLastError());
            std::cout << "Accept failed: " << WSAGetLastError() << std::endl;
            break;
        }
 
        //printf("Accept client IP:[%s]\n", inet_ntoa(addrCli.sin_addr));
        std::cout << "Accept client IP: " << inet_ntoa(addrCli.sin_addr) << std::endl;
 
        // 6.发送数据
        sprintf_s(sendBuf, "hello client!\n");
        int iSend = send(sockConn, sendBuf, strlen(sendBuf) + 1, 0);
        if (iSend == SOCKET_ERROR) {
            std::cout << "send failed!\n";
            break;
        }
 
        // 7.接收数据
        recv(sockConn, recvBuf, 100, 0);
        std::cout << recvBuf << std::endl;
 
        // 关闭套接字
        closesocket(sockConn);
    }
 
 
    // 8.关闭套接字
    closesocket(sockSrv);
 
    // 9.清理套接字库
    WSACleanup();
 
    return 0;
}

2). 客户端

初始化套接字库
对应图中socket()

?
1
2
3
4
5
6
7
8
9
10
11
12
WORD wVersion;
WSADATA wsaData;
int err;
 
// 可以理解为1.1
wVersion = MAKEWORD(1, 1);  // 例:MAKEWORD(a, b) --> b | a << 8 将a左移8位变成高位与b合并起来
 
// 启动
err = WSAStartup(wVersion, &wsaData);
 
// 创建TCP套接字
SOCKET sockCli = socket(AF_INET, SOCK_STREAM, 0);

连接服务器
对应图中connect()

?
1
2
// 连接服务器
int err_log = connect(sockCli, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));

发送数据到服务器
对应图中write()

?
1
2
char sendBuf[] = "你好,服务器,我是客户端!";
send(sockCli, sendBuf, strlen(sendBuf) + 1, 0);

接收服务器的数据
对应图中read()

?
1
2
char recvBuf[100];
recv(sockCli, recvBuf, sizeof(recvBuf), 0);

关闭套接字并清除套接字库
对应图中close()

?
1
2
closesocket(sockCli);
WSACleanup();

具体实现代码

?
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
#include <iostream>
#include <WinSock2.h>
 
 
#pragma comment(lib, "ws2_32.lib")
 
 
int main(void) {
 
    // 1.初始化套接字库
    WORD wVersion;
    WSADATA wsaData;
    int err;
 
    // 可以理解为1.1
    wVersion = MAKEWORD(1, 1);  // 例:MAKEWORD(a, b) --> b | a << 8 将a左移8位变成高位与b合并起来
 
    // 启动
    err = WSAStartup(wVersion, &wsaData);
    if (err != 0) {
        return err;
    }
    // 检查:网络地位不等于1 || 网络高位不等于1
    if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {
        // 清理套接字库
        WSACleanup();
        return -1;
    }
 
    // 创建TCP套接字
    SOCKET sockCli = socket(AF_INET, SOCK_STREAM, 0);
 
    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");  // 服务器地址
    addrSrv.sin_port = htons(6000);     // 端口号
    addrSrv.sin_family = AF_INET;       // 地址类型(ipv4)
 
    // 2.连接服务器
    int err_log = connect(sockCli, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));
    if (err_log == 0) {
        printf("连接服务器成功!\n");
    
    } else {
        printf("连接服务器失败!\n");
        return -1;
    }
 
 
    char recvBuf[100];
    char sendBuf[] = "你好,服务器,我是客户端!";
    // 3.发送数据到服务器
    send(sockCli, sendBuf, strlen(sendBuf) + 1, 0);
 
    // 4.接收服务器的数据
    recv(sockCli, recvBuf, sizeof(recvBuf), 0);
    std::cout << recvBuf << std::endl;
 
 
    // 5.关闭套接字并清除套接字库
    closesocket(sockCli);
    WSACleanup();
 
    system("pause");
 
    return 0;
}

运行效果:

C++ Socket实现TCP与UDP网络编程

3). TCP聊天小项目

下面是根据上面的代码修改的一个聊天小项目(使用到了多线程)

只有一个服务器,服务器一直开启等待客户端连接;
客户都安可以开启多个,且可以一直连续的与服务器进行发送接收消息;
服务器给客户端发送数据,得通过1 - 9来区分到底给那个客户端发送消息,例如给第二个客户端发送消息:2你好,客户端
客户端那边接收到的数据是:你好,客户端

服务器代码

?
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#include <iostream>
#include <WinSock2.h>
#include <stdio.h>
#include <Windows.h>
#include <process.h>
#include <vector>
#include <conio.h>
#include <string.h>
#include <string>
 
#pragma comment(lib, "ws2_32.lib")
 
 
SOCKET sockSrv;
std::vector<SOCKET> vec_sockConn;
std::vector<SOCKADDR_IN> vec_sockaddr_in;
std::vector<int> vec_sockIndex;
 
 
// 这个结构体用作线程参数
typedef struct SERVER_CLIENT {
    SOCKET server;
    SOCKADDR_IN client;
    int clientIndex;
}SC;
 
 
 
// 判断有没有断开连接
bool IsSocketClosed(SOCKET clientSocket) {
    bool ret = false;
    HANDLE closeEvent = WSACreateEvent();
    WSAEventSelect(clientSocket, closeEvent, FD_CLOSE);
 
    DWORD dwRet = WaitForSingleObject(closeEvent, 0);
 
    if (dwRet == WSA_WAIT_EVENT_0)
        ret = true;
    else if (dwRet == WSA_WAIT_TIMEOUT)
        ret = false;
 
    WSACloseEvent(closeEvent);
    return ret;
}
 
 
// 接收请求
unsigned int WINAPI  ThreadAccept(LPVOID p) {
    static int i = 0;
    while (1) {
        SOCKADDR_IN addrCli;
        int len = sizeof(SOCKADDR);
 
        // 5.接收连接请求,返回针对客户端的套接字
        SOCKET sockConn = accept(sockSrv, (SOCKADDR *)&addrCli, &len);
        if (sockConn == SOCKET_ERROR) {
            printf("Accept failed:%d", WSAGetLastError());
        }
 
        // 存储当前服务器与客户端 连接绑定的socket
        vec_sockIndex.emplace_back(i++);
        vec_sockaddr_in.emplace_back(addrCli);
        vec_sockConn.emplace_back(sockConn);
 
        printf("\033[0;%d;40m客户端[%d]上线\033[0m\n", 31, i);
    }
    
 
    return 0;
}
 
unsigned int WINAPI  _ThreadRecv(LPVOID p) {
    char recvBuf[100];
    memset(recvBuf, 0, 100);
 
    SC _sc = *(SC *)p;
    
    while (1) {
        Sleep(20);
 
        if (IsSocketClosed(_sc.server) == true) {
            printf("客户端 [%d] 断开连接!\n", _sc.clientIndex + 1);
            break;
        }
 
 
        // 接收数据
        recv(_sc.server, recvBuf, 100, 0);
        if (strlen(recvBuf) == 0) {
            continue;
        }
    
        printf("接收到客户端 [%d] 的消息:%s\n", _sc.clientIndex + 1, recvBuf);
        memset(recvBuf, 0, 100);
    }
    return 0;
}
 
unsigned int WINAPI  ThreadRecv(LPVOID p) {
 
    static int index = 0;
 
    while (1) {
        // 还没有客户端与服务器进行连接
        if (vec_sockConn.size() == 0) {
            continue;
        }
 
        // 接收线程已经开启和客户端个数相等
        if (vec_sockConn.size()  == index) {
            continue;
        }
 
        SC sc;
        sc.server = vec_sockConn.at(index);
        sc.client = vec_sockaddr_in.at(index);
        sc.clientIndex = vec_sockIndex.at(index);
 
        HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, _ThreadRecv, (void *)&sc, 0, NULL);
 
        index++;
        Sleep(20);
    }
 
    return 0;
}
 
 
 
int main(void) {
 
    // 1.初始化套接字库
    WORD wVersion;
    WSADATA wsaData;
    int err;
 
    // 设置版本,可以理解为1.1
    wVersion = MAKEWORD(1, 1);  // 例:MAKEWORD(a, b) --> b | a << 8 将a左移8位变成高位与b合并起来
 
    // 启动
    err = WSAStartup(wVersion, &wsaData);
    if (err != 0) {
        return err;
    }
    // 检查:网络低位不等于1 || 网络高位不等于1
    if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {
        // 清理套接字库
        WSACleanup();
        return -1;
    }
 
    // 2.创建tcp套接字       // AF_INET:ipv4   AF_INET6:ipv6
    sockSrv = socket(AF_INET, SOCK_STREAM, 0);
 
    // 准备绑定信息
    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);   // 设置绑定网卡
    addrSrv.sin_family = AF_INET;       // 设置绑定网络模式
    addrSrv.sin_port = htons(6000);     // 设置绑定端口
    // hton: host to network  x86:小端    网络传输:htons大端
 
    // 3.绑定到本机
    int retVal = bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));
    if (retVal == SOCKET_ERROR) {
        printf("Failed bind:%d\n", WSAGetLastError());
        return -1;
    }
 
    // 4.监听,同时接收10个链接
    if (listen(sockSrv, 10) == SOCKET_ERROR) {
        printf("Listen failed:%d", WSAGetLastError());
        return -1;
    }
 
    std::cout << "Server start at port: 6000" << std::endl;
 
 
    // 线程句柄             // 创建线程
    HANDLE hThread_1 = (HANDLE)_beginthreadex(NULL, 0, ThreadAccept, NULL, 0, NULL);
    HANDLE hThread_2 = (HANDLE)_beginthreadex(NULL, 0, ThreadRecv, NULL, 0, NULL);
 
 
    //uiInit();
    //editPrint(0, ">");
 
 
    char sendBuf[100];
    while (1) {
 
        //printf("请输入发送内容:");
 
        char c = getchar();             // 输入发送给谁
        scanf_s("%s", sendBuf, 100);    // 输入发送的内容
 
        if (strlen(sendBuf) == 0) {
            printf("输入内容为空或者超长!\n");
        }
 
        // 1 至 9
        if (c < '1' || c > '9' || vec_sockConn.size() == 0 || c - '0' >= vec_sockConn.size() + 1) {
            while ((c = getchar()) != '\n');    // 清空输入缓冲区
            memset(sendBuf, 0, 100);
            printf("输入内容不符合规则!\n");
            continue;
        }
 
 
 
        // 发送数据
        int index = --c - '0'// 因为下标是从零开始的,所以c要先自减
        int iSend = send(vec_sockConn.at(index) , sendBuf, strlen(sendBuf) + 1, 0);
        if (iSend == SOCKET_ERROR) {
            std::cout << "send failed!\n";
            break;
        }
 
 
        memset(sendBuf, 0, 100);
        while ((c = getchar()) != '\n');    // 清空输入缓冲区
    }
 
    // 关闭套接字
    std::vector<SOCKET>::iterator it = vec_sockConn.begin();
    for (; it != vec_sockConn.end(); it++) {
        closesocket((SOCKET)(*it));
    }
 
 
    WaitForSingleObject(hThread_1, INFINITE);
    WaitForSingleObject(hThread_2, INFINITE);
 
    CloseHandle(hThread_1);
    CloseHandle(hThread_2);
 
    // 7.关闭套接字
    closesocket(sockSrv);
 
    // 8.清理套接字库
    WSACleanup();
 
    return 0;
}

客户端

?
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
117
118
119
120
121
122
123
#include <iostream>
#include <WinSock2.h>
#include <process.h>
#include <stdio.h>
 
#pragma comment(lib, "ws2_32.lib")
 
SOCKET sockCli;
 
 
// 判断有没有断开连接
bool IsSocketClosed(SOCKET clientSocket) {
    bool ret = false;
    HANDLE closeEvent = WSACreateEvent();
    WSAEventSelect(clientSocket, closeEvent, FD_CLOSE);
 
    DWORD dwRet = WaitForSingleObject(closeEvent, 0);
 
    if (dwRet == WSA_WAIT_EVENT_0)
        ret = true;
    else if (dwRet == WSA_WAIT_TIMEOUT)
        ret = false;
 
    WSACloseEvent(closeEvent);
    return ret;
}
 
 
unsigned int WINAPI  ThreadRecv(LPVOID p) {
    char recvBuf[100];
    memset(recvBuf, 0, 100);
 
    while (1) {
        Sleep(20);
 
        if (IsSocketClosed(sockCli) == true) {
            printf("服务器 断开连接!\n");
            break;
        }
 
        // 接收服务器的数据
        recv(sockCli, recvBuf, sizeof(recvBuf), 0);
        if (strlen(recvBuf) == 0) continue;
 
        std::cout << recvBuf << std::endl;
        memset(recvBuf, 0, 100);
    }
 
 
    return 0;
}
 
int main(void) {
 
    // 1.初始化套接字库
    WORD wVersion;
    WSADATA wsaData;
    int err;
 
    // 可以理解为1.1
    wVersion = MAKEWORD(1, 1);  // 例:MAKEWORD(a, b) --> b | a << 8 将a左移8位变成高位与b合并起来
 
    // 启动
    err = WSAStartup(wVersion, &wsaData);
    if (err != 0) {
        return err;
    }
    // 检查:网络地位不等于1 || 网络高位不等于1
    if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {
        // 清理套接字库
        WSACleanup();
        return -1;
    }
 
    // 创建TCP套接字
    sockCli = socket(AF_INET, SOCK_STREAM, 0);
 
    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");  // 服务器地址
    addrSrv.sin_port = htons(6000);     // 端口号
    addrSrv.sin_family = AF_INET;       // 地址类型(ipv4)
 
    // 连接服务器
    int err_log = connect(sockCli, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));
    if (err_log == 0) {
        printf("连接服务器成功!\n");
 
    } else {
        printf("连接服务器失败!\n");
        return -1;
    }
 
    // 线程句柄             // 创建线程
    HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadRecv, NULL, 0, NULL);
 
 
    char sendBuf[100];
    while (1) {
 
        //printf("请输入发送内容:");
        scanf_s("%s", sendBuf, 100);
 
        // 发送数据到服务器
        send(sockCli, sendBuf, strlen(sendBuf) + 1, 0);
 
        memset(sendBuf, 0, 100);
        char c;
        while ((c = getchar()) != '\n');
    }
 
 
    WaitForSingleObject(hThread, INFINITE);
    CloseHandle(hThread);
 
 
    // 关闭套接字并清除套接字库
    closesocket(sockCli);
    WSACleanup();
 
    system("pause");
 
    return 0;
}

运行效果:

C++ Socket实现TCP与UDP网络编程

UDP

UDP就比较简单了,步骤比tcp要少一些。

连接过程图:

C++ Socket实现TCP与UDP网络编程

1). 服务器

初始化套接字库

?
1
2
3
4
5
WORD wVersion;
WSADATA wsaData;
int err;
 
wVersion = MAKEWORD(1, 1);

创建套接字

?
1
SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0);

绑定

?
1
2
// SOCKADDR_IN addrSrv; 省略了定义和赋值
bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));

接收数据

?
1
2
char recvBuf[100];
recvfrom(sockSrv, recvBuf, 100, 0, (SOCKADDR *)&addrCli, &len);

发送数据

?
1
2
char sendBuf[] = "hello Client,I'm Server!\n";
sendto(sockSrv, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR *)&addrCli, len);

关闭

?
1
2
closesocket(sockSrv);
WSACleanup();

具体实现代码

?
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
#include <WinSock2.h>
#include <iostream>
 
#pragma comment(lib, "ws2_32.lib")
 
int main(void) {
    // 初始化套接字库
    WORD wVersion;
    WSADATA wsaData;
    int err;
 
    wVersion = MAKEWORD(1, 1);
    err = WSAStartup(wVersion, &wsaData);
    if (err != 0) {
        return err;
    }
 
    if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {
        WSACleanup();
        return -1;
    }
 
    // 创建套接字
    SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0);
 
    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    addrSrv.sin_family = AF_INET;
    addrSrv.sin_port = htons(6001);
 
    // 绑定到本机6001端口
    bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));
 
    // 接收请求,处理请求
    SOCKADDR_IN addrCli;
    int len = sizeof(SOCKADDR);
 
    char sendBuf[] = "hello Client,I'm Server!\n";
    char recvBuf[100];
 
    std::cout << "start UDP server with port 6001" << std::endl;
    while (1) {
        // 接收数据
        recvfrom(sockSrv, recvBuf, 100, 0, (SOCKADDR *)&addrCli, &len);
        std::cout << "Recv:" << recvBuf << std::endl;
 
        // 发送数据
        sendto(sockSrv, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR *)&addrCli, len);
        std::cout << "Send:" << sendBuf << std::endl;
    }
 
    closesocket(sockSrv);
    WSACleanup();
 
    return 0;
}

2). 客户端

初始化套接字库

?
1
2
3
4
5
WORD wVersion;
WSADATA wsaData;
int err;
 
wVersion = MAKEWORD(1, 1);

创建UDP套接字

?
1
2
SOCKET sockCli = socket(AF_INET, SOCK_DGRAM, 0);
SOCKADDR_IN addrSrv;

接收数据

?
1
2
char recvBuf[100];
recvfrom(sockCli, recvBuf, 100, 0, (SOCKADDR *)&addrCli, &len);

发送数据

?
1
2
char sendBuf[] = "hello Client,I'm Server!\n";
sendto(sockCli, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR *)&addrSrv, len);

关闭

?
1
2
closesocket(sockSrv);
WSACleanup();

具体实现代码

?
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
#include <WinSock2.h>
#include <iostream>
 
#pragma comment(lib, "ws2_32.lib")
 
 
int main(void) {
 
    // 初始化套接字库
    WORD wVersion;
    WSADATA wsaData;
    int err;
 
    wVersion = MAKEWORD(1, 1);
    err = WSAStartup(wVersion, &wsaData);
    if (err != 0) {
        return err;
    }
 
    if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {
        WSACleanup();
        return -1;
    }
 
    // 创建UDP套接字
    SOCKET sockCli = 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(6001);
 
    SOCKADDR_IN addrCli;
    int len = sizeof(SOCKADDR);
 
    char sendBuf[] = "hello, I'm Client!\n";
    char recvBuf[100];
 
    std::cout << "send to Server: " << sendBuf << std::endl;
    sendto(sockCli, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR *)&addrSrv, len);
 
    recvfrom(sockCli, recvBuf, 100, 0, (SOCKADDR *)&addrCli, &len);
    std::cout << "recv from: " << recvBuf << std::endl;
 
 
    closesocket(sockCli);
    WSACleanup();
 
    system("pause");
    return 0;
}

运行效果:

C++ Socket实现TCP与UDP网络编程

总结

socket的具体细节用法我不太清楚,现阶段也只是熟悉TCP的一些简单操作,UDP的话也还不是太懂,不懂的是不知道在具体项目中该如何进行使用它们。
那个TCP的小项目也只是自己琢磨搞出来的,不知掉具体项目会不会这样去写!

到此这篇关于C++ Socket实现TCP与UDP网络编程的文章就介绍到这了,更多相关C++ Socket实现TCP与UDP内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/cpp_learner/article/details/121798854

延伸 · 阅读

精彩推荐
  • C/C++C/C++中二进制文件&顺序读写详解及其作用介绍

    C/C++中二进制文件&顺序读写详解及其作用介绍

    这篇文章主要介绍了C/C++中二进制文件&顺序读写详解及其作用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可...

    我是小白呀9082021-12-28
  • C/C++详解C++11原子类型与原子操作

    详解C++11原子类型与原子操作

    这篇文章主要介绍了C++11原子类型与原子操作的相关资料,帮助大家更好的理解和学习c++,感兴趣的朋友可以了解下...

    Dabelv11102021-09-22
  • C/C++C++实现LeetCode(130.包围区域)

    C++实现LeetCode(130.包围区域)

    这篇文章主要介绍了C++实现LeetCode(130.包围区域),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...

    Grandyang10652021-12-06
  • C/C++一篇文章带你使用C语言编写内核

    一篇文章带你使用C语言编写内核

    内核是操作系统最核心的内容,主要提供硬件抽象层、磁盘及文件系统控制、多任务等功能,由于其涉及非常广泛的计算机知识,很少被人们所熟悉,因而...

    Anita-Sun10352021-12-15
  • C/C++C语言之快速排序案例详解

    C语言之快速排序案例详解

    这篇文章主要介绍了C语言之快速排序案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...

    小尹同学11212021-12-07
  • C/C++VC++中HTControl的CHTButton按钮控件类用法实例解析

    VC++中HTControl的CHTButton按钮控件类用法实例解析

    这篇文章主要介绍了VC++中HTControl的CHTButton按钮控件类用法,对于大家进行VC++项目开发有一定的帮助作用,需要的朋友可以参考下...

    C++教程网7912021-01-25
  • C/C++显示内存状态示例分享

    显示内存状态示例分享

    这篇文章主要介绍了显示内存状态示例,代码简单,下面直接看代码,需要的朋友可以参考下...

    C语言程序设计4602021-01-16
  • C/C++C++之函数的重载

    C++之函数的重载

    这篇文章主要介绍了c++函数重载的相关知识,文章讲解的非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下...

    ALL IN C4332022-02-17