socket编程分为tcp和udp两个模块,其中tcp是可靠的、安全的,常用于发送文件等,而udp是不可靠的、不安全的,常用作视频通话等。
如下图:
头文件与库:
#include <winsock2.h>#pragma comment(lib, "ws2_32.lib")
准备工作:
创建工程后,首先右键工程,选择属性
然后选择 c/c++ – 预处理器 – 预处理器定义
将字符串 _winsock_deprecated_no_warnings 添加到里面去,点击应用即可!
连接过程图:
创建tcp服务器和客户端都是按照上图的步骤来操作的!
初始化套接字库
对应图中socket()
word wversion;wsadata wsadata;int err;// 设置版本,可以理解为1.1wversion = makeword(1, 1);// 例:makeword(a, b) --> b | a << 8 将a左移8位变成高位与b合并起来// 启动err = wsastartup(wversion, &wsadata);
创建tcp套接字
对应图中socket()
// af_inet:ipv4 af_inet6:ipv6socket socksrv = socket(af_inet, sock_stream, 0);
绑定到本机
对应图中bind()
// 准备绑定信息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()
// 同时能接收10个链接,主要看参数二的设置个数listen(socksrv, 10);
接收连接请求,返回针对客户端的套接字
对应图中accept()
socket sockconn = accept(socksrv, (sockaddr *)&addrcli, &len);
发送数据
对应图中write()
sprintf_s(ndbuf, "hello client!\n");int ind = nd(sockconn, ndbuf, strlen(ndbuf) + 1, 0);
接收数据
对应图中read()
recv(sockconn, recvbuf, 100, 0);
关闭套接字
对应图中clo()
closocket(sockconn);
清理套接字库
wsacleanup();
具体实现代码:
#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.1wversion = makeword(1, 1);// 例:makeword(a, b) --> b | a << 8 将a左移8位变成高位与b合并起来// 启动err = wsastartup(wversion, &wsadata);if (err != 0) {return err;}// 检查:网络低位不等于1 || 网络高位不等于1if (lobyte(wsadata.wversion) != 1 || hibyte(wsadata.wversion) != 1) {// 清理套接字库wsacleanup();return -1;}// 2.创建tcp套接字// af_inet:ipv4 af_inet6:ipv6socket 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 << "rver start at port: 6000" << std::e网络市场营销ndl;sockaddr_in addrcli;int len = sizeof(sockaddr);char recvbuf[100];char ndbuf[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(ndbuf, "hello client!\n");int ind = nd(sockconn, ndbuf, strlen(ndbuf) + 1, 0);if (ind == socket_error) {std::cout << "nd failed!\n";break;}// 7.接收数据recv(sockconn, recvbuf, 100, 0);std::cout << recvbuf << std::endl;// 关闭套接字closocket(sockconn);}// 8.关闭套接字closocket(socksrv);// 9.清理套接字库wsacleanup();return 0;}
初始化套接字库
对应图中socket()
word wversion;wsadata wsadata;int err;// 可以理解为1.1wversion = 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()
// 连接服务器int err_log = connect(sockcli, (sockaddr *)&addrsrv, sizeof(sockaddr));
发送数据到服务器
对应图中write()
char ndbuf[] = "你好,服务器,我是客户端!";nd(sockcli, ndbuf, strlen(ndbuf) + 1, 0);
接收服务器的数据
对应图中read()
char recvbuf[100];recv(sockcli, recvbuf, sizeof(recvbuf), 0);
关闭套接字并清除套接字库
对应图中clo()
closocket(sockcli);wsacleanup();
具体实现代码:
#include <iostream>#include <winsock2.h>#pragma comment(lib, "ws2_32.lib")int main(void) {// 1.初始化套接字库word wversion;wsadata wsadata;int err;// 可以理解为1.1wversion = makeword(1, 1);// 例:makeword(a, b) --> b | a << 8 将a左移8位变成高位与b合并起来// 启动err = wsastartup(wversion, &wsadata);if (err != 0) {return err;}// 检查:网络地位不等于1 || 网络高位不等于1if (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");} el {printf("连接服务器失败!\n");return -1;}char recvbuf[100];char ndbuf[] = "你好,服务器,我是客户端!";// 3.发送数据到服务器nd(sockcli, ndbuf咏菊最好的诗句, strlen(ndbuf) + 1, 0);// 4.接收服务器的数据recv(sockcli, recvbuf, sizeof(recvbuf), 0);std::cout << recvbuf << std::endl;// 5.关闭套接字并清除套接字库closocket(sockcli);wsacleanup();system("pau");return 0;}
运行效果:
下面是根据上面的代码修改的一个聊天小项目(使用到了多线程)
只有一个服务器,服务器一直开启等待客户端连接;
客户都安可以开启多个,且可以一直连续的与服务器进行发送接收消息;
服务器给客户端发送数据,得通过1 – 9来区分到底给那个客户端发送消息,例如给第二个客户端发送消息:2你好,客户端
客户端那边接收到的数据是:你好,客户端
服务器代码:
#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 rver_client {socket rver;sockaddr_in client;int clientindex;}sc;// 判断有没有断开连接bool issocketclod(socket clientsocket) {bool ret = fal;handle cloevent = wsacreateevent();wsaeventlect(clientsocket, cloevent, fd_clo);dword dwret = waitforsingleobject(cloevent, 0);if (dwret == wsa_wait_event_0)ret = true;el if (dwret == wsa_wait_timeout)ret = fal;wsacloevent(cloevent);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());}// 存储当前服务器与客户端 连接绑定的socketvec_sockindex.emplace_back(i++);vec_sockaddr_in.emplace_back(addrcli);vec_sockconn.emplace_back(sockconn);printf("3[0;%d;40m客户端[%d]上线3[0m\n", 31, i);}return 0;}unsigned int winapi _threadrecv(lpvoid p) {char recvbuf[100];memt(recvbuf, 0, 100);sc _sc = *(sc *)p;while (1) {sleep(20);if (issocketclod(_sc.rver) == true) {printf("客户端 [%d] 断开连接!\n", _sc.clientindex + 1);break;}// 接收数据recv(_sc.rver, recvbuf, 100, 0);if (strlen(recvbuf) == 0) {continue;}printf("接收到客户端 [%d] 的消息:%s\n", 开光吉祥物_sc.clientindex + 1, recvbuf);memt(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.rver = 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.1wversion = makeword(1, 1);// 例:makeword(a, b) --> b | a << 8 将a左移8位变成高位与b合并起来// 启动err = wsastartup(wversion, &wsadata);if (err != 0) {return err;}// 检查:网络低位不等于1 || 网络高位不等于1if (lobyte(wsadata.wversion) != 1 || hibyte(wsadata.wversion) != 1) {// 清理套接字库wsacleanup();return -1;}// 2.创建tcp套接字// af_inet:ipv4 af_inet6:ipv6socksrv = 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 << "rver 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 ndbuf[100];while (1) {//printf("请输入发送内容:");char c = getchar();// 输入发送给谁scanf_s("%s", ndbuf, 100);// 输入发送的内容if (strlen(ndbuf) == 0) {printf("输入内容为空或者超长!\n");}// 1 至 9if (c < '1' || c > '9' || vec_sockconn.size() == 0 || c - '0' >= vec_sockconn.size() + 1) {while ((c = getchar()) != '\n');// 清空输入缓冲区memt(ndbuf, 0, 100);printf("输入内容不符合规则!\n");continue;}// 发送数据int index = --c - '0';// 因为下标是从零开始的,所以c要先自减int ind = nd(vec_sockconn.at(index) , ndbuf, strlen(ndbuf) + 1, 0);if (ind == socket_error) {std::cout << "nd failed!\n";break;}memt(ndbuf, 0, 100);while ((c = getchar()) != '\n');// 清空输入缓冲区}// 关闭套接字std::vector<socket>::iterator it = vec_sockconn.begin();for (; it != vec_sockconn.end(); it++) {closocket((socket)(*it));}waitforsingleobject(hthread_1, infinite);waitforsingleobject(hthread_2, infinite);clohandle(hthread_1);clohandle(hthread_2);// 7.关闭套接字closocket(socksrv);// 8.清理套接字库wsacleanup();return 0;}
客户端:
#include <iostream>#include <winsock2.h>#include <process.h>#include <stdio.h>#pragma comment(lib, "ws2_32.lib")socket sockcli;// 判断有没有断开连接bool issocketclod(socket clientsocket) {bool ret = fal;handle cloevent = wsacreateevent();wsaeventlect(clientsocket, cloevent, fd_clo);dword dwret = waitforsingleobject(cloevent, 0);if (dwret == wsa_wait_event_0)ret = true;el if (dwret == wsa_wait_timeout)ret = fal;wsacloevent(cloevent);return ret;}unsigned int winapi threadrecv(lpvoid p) {char recvbuf[100];memt(recvbuf, 0, 100);while (1) {sleep(20);if (issocketclod(sockcli) == true) {printf("服务器 断开连接!\n");break;}// 接收服务器的数据recv(sockcli, recvbuf, sizeof(recvbuf), 0);if (strlen(recvbuf) == 0) continue;std::cout << recvbuf << std::endl;memt(recvbuf, 0, 100);}return 0;}int main(void) {// 1.初始化套接字库word wversion;wsadata wsadata;int err;// 可以理解为1.1wversion = makeword(1, 1);// 例:makeword(a, b) --> b | a << 8 将a左移8位变成高位与b合并起来// 启动err = wsastartup(wversion, &wsadata);if (err != 0) {return err;}// 检查:网络地位不等于1 || 网络高位不等于1if (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");} el {printf("连接服务器失败!\n");return -1;}// 线程句柄// 创建线程handle hthread = (handle)_beginthreadex(null, 0, threadrecv, null, 0, null);char ndbuf[100];while (1) {//printf("请输入发送内容:");scanf_s("%s", ndbuf, 100);// 发送数据到服务器nd(sockcli, ndbuf, strlen(ndbuf) + 1, 0);memt(ndbuf, 0, 100);char c;while ((c = getchar()) != '\n');}waitforsingleobject(hthread, infinite);clohandle(hthread);// 关闭套接字并清除套接字库closocket(sockcli);wsacleanup();system("pau");return 0;}
运行效果:
udp就比较简单了,步骤比tcp要少一些。
连接过程图:
初始化套接字库
word wversion;wsadata wsadata;int err;wversion = makeword(1, 1);
创建套接字
socket socksrv = socket(af_inet, sock_dgram, 0);
绑定
// sockaddr_in addrsrv; 省略了定义和赋值bind(socksrv, (sockaddr *)&addrsrv, sizeof(sockaddr));
接收数据
char recvbuf[100];recvfrom(socksrv, recvbuf, 100, 0, (sockaddr *)&addrcli, &len);
发送数据
char ndbuf[] = "hello client,i'm rver!\n";ndto(socksrv, ndbuf, strlen(ndbuf) + 1, 0, (sockaddr *)&addrcli, len);
关闭
closocket(socksrv);wsacleanup();
具体实现代码:
#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 ndbuf[] = "hello client,i'm rver!\n";char recvbuf[100];std::cout << "start udp rver with port 6001" << std::endl;while (1) {// 接收数据recvfrom(socksrv, recvbuf, 100, 0, (sockaddr *)&addrcli, &len);std::cout << "recv:" << recvbuf << std::endl;// 发送数据ndto(socksrv, ndbuf, strlen(ndbuf) + 1, 0, (sockaddr *)&addrcli, len);std::cout << "nd:" << ndbuf << std::endl;}closocket(socksrv);wsacleanup();return 0;}
初始化套接字库
word wversion;wsadata wsadata;int err;wversion = makeword(1, 1);
创建udp套接字
socket sockcli = socket(af_inet, sock_dgram, 0);sockaddr_in addrsrv;
接收数据
char recvbuf[100];recvfrom(sockcli, recvbuf, 100, 0, (sockaddr *)&addrcli, &len);
发送数据
char ndbuf[] = "hello client,i'm rver!\n";ndto(sockcli, ndbuf, strlen(ndbuf) + 1, 0, (sockaddr *)&addrsrv, len);
关闭
closocket(socksrv);wsacleanup();
具体实现代码:
#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 ndbuf[] = "hello, i'm client!\n";char recvbuf[100];std::cout << "nd to rver: " << ndbuf << std::endl;ndto(sockcli, ndbuf, strlen(ndbuf) + 1, 0, (sockaddr *)&addrsrv, len);recvfrom(sockcli, recvbuf, 100, 0, (sockaddr *)&addrcli, &len);std::cout << "recv from: " << recvbuf << std::endl;closocket(sockcli);wsacleanup();system("pau");return 0;}
运行效果:
socket的具体细节用法我不太清楚,现阶段也只是熟悉tcp的一些简单操作,udp的话也还不是太懂,不懂的是不知道在具体项目中该如何进行使用它们。
那个tcp的小项目也只是自己琢磨搞出来的,不知掉具体项目会不会这样去写!
到此这篇关于c++ socket实现tcp与udp网络编程的文章就介绍到这了,更多相关c++ socket实现tcp与udp内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!
本文发布于:2023-04-04 16:35:51,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/63279c96cbe56eb420f6e85999ec1e06.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:C++ Socket实现TCP与UDP网络编程.doc
本文 PDF 下载地址:C++ Socket实现TCP与UDP网络编程.pdf
留言与评论(共有 0 条评论) |