0


C/C++网络编程详解(Windows版)

文章目录


教程推荐:

人工智能教程,点击这里查看,通俗易懂,风趣幽默

C/C++教程,点击这里查看,以项目为主导从入门到精通

前言

相比于基础,网络编程就要复杂一些,但其实也有固定格式,记住即可。

需要的头文件和库:

  1. #include<WinSock2.h>#pragmacomment(lib,"ws2_32.lib")

一、服务器

主要流程及主要函数:

  1. 网络环境初始化:WSAStartup
  2. 创建服务器套接字:socket
  3. 绑定本机IP和端口:bind
  4. 监听客户端:listen
  5. 等待客户端连接:accept
  6. 发送消息:send
  7. 接收消息:recv
  8. 关闭socket:closesocket
  9. 清除网络环境:WSACleanup

WSAStartup函数

正常使用

函数原型:

  1. intWSAStartup(
  2. WORD wVersionRequested,//版本号,使用MAKEWORD宏生成
  3. LPWSADATA lpWSAData //数据);//返回值:0代表成功,否则失败

使用方法:

  1. #include<WinSock2.h>#include<iostream>#pragmacomment(lib,"ws2_32")usingnamespace std;intmain(){
  2. WSADATA data;int ret=WSAStartup(MAKEWORD(2,2),&data);if(ret){
  3. cout <<"初始化网络错误!"<< endl;return-1;}}

该函数用于初始化网络环境,参数基本上是固定写法,记住即可,必须要有。

函数详解

该函数实则是用来加载Windows Socket动态库的

wVersionRequested参数用来指定准备加载动态库的版本号,高字节为库文件的副版本,低字节指定主版本,MAKEWORD(X,Y)宏用于生成该参数,其中X为高字节,Y为低字节

lpWSAData 为指向WSADATA结构体的指针,该参数用于返回被加载动态库的有关信息

  1. typedefstructWSAData{
  2. WORD wVersion;//期望调用者使用的socket版本(或实际返回的socket版本,可根据此参数判断返回的版本号是否正确,可通过HIBYTE宏取得高字节,LOBYTE宏取得低字节)
  3. WORD wHighVersion;//本机Dll支持的最高版本unsignedshort iMaxSockets;//一个进程最多可以打开的套接字数量(2.0版本后忽略此值)unsignedshort iMaxUdpDg;//一个进程发送或接收的最大数据报长度char FAR * lpVendorInfo;//厂商专有信息(2.0版本后忽略此值)char szDescription[WSADESCRIPTION_LEN+1];//DLL的描述信息char szSystemStatus[WSASYS_STATUS_LEN+1];//DLL的状态信息

socket函数

函数原型:

  1. SOCKET socket(int af,//地址类型,常用IPv4地址:AF_INET,和IPv6地址:AF_INET6int type,//套接字类型,常用TCP协议:SOCK_STREAM,UDP协议:SOCK_DGRAMint protocol //协议类型,一般填0,自动选择即可);//返回值,INVALID_SOCKET失败,该宏实则定义为-1,否则成功

使用:

  1. SOCKET sock=socket(AF_INET,SOCK_STREAM,0);if(sock ==-1){
  2. cout <<"创建套接字失败";return-1;}

该代码创建了IPv4类型的地址,TCP协议的套接字

完整视图:
在这里插入图片描述

bind函数

函数原型:

  1. intbind(
  2. SOCKET s,//创建的socket
  3. sockaddr * name,//包含地址和端口的结构体int namelen //sockaddr 结构长度);//返回值:返回SOCKET_ERROR失败,该宏被定义为-1,否则成功,返回值为0

使用:

  1. #define_WINSOCK_DEPRECATED_NO_WARNINGS//vs环境下必须定义,否则无法使用inet_addr函数
  2. sockaddr_in addr;
  3. addr.sin_family = AF_INET;//地址为IPv4协议
  4. addr.sin_port =htons(9999);//端口为9999
  5. addr.sin_addr.S_un.S_addr =inet_addr("127.0.0.1");//具体绑定本机的地址
  6. ret=bind(sock,(sockaddr*)&addr,sizeof(addr));//绑定if(ret ==-1){
  7. cout <<"绑定地址端口失败";return-1;}

完整视图:
在这里插入图片描述

listen函数

函数原型:

  1. intlisten(
  2. SOCKET s,//要监听的socketint backlog //等待连接的最大队列长度);//返回值:返回SOCKET_ERROR失败,该宏被定义为-1,否则成功,返回值为0

使用:

  1. ret=listen(sock,5);if(ret ==-1){
  2. cout <<"监听套接字失败";return-1;}

完成代码:
在这里插入图片描述

accept函数

函数原型:

  1. SOCKET accept(
  2. SOCKET s,//接收的socket
  3. sockaddr* addr,//接收到客户端的地址信息int* addrlen //地址信息长度);//返回值:返回INVALID_SOCKET失败,该宏定义为-1,否则成功返回客户端的套接字,可进行发送和接收消息

使用:

  1. sockaddr addrCli;int len =sizeof(addrCli);
  2. SOCKET sockCli=accept(sock,&addrCli,&len);if(sockCli ==-1){
  3. cout <<"接收客户端连接失败";return-1;}

完整代码视图:
在这里插入图片描述

send函数

函数原型:

  1. intsend(
  2. SOCKET s,char* buf,//要发送的内容int len,//内容长度int flags //一般为0,拷贝到程序中就立即删除内核中的数据,或MSG_DONTROUTE:要求传输层不要将数据路由出去,MSG_OOB:标志数据应该被带外发送);//返回值:-1(或宏SOCKET_ERROR)表示发送失败,否则返回发送成功的字节数

使用:

  1. char buf[0xFF]="我是服务器";
  2. ret=send(sockCli, buf,strlen(buf),0);if(ret ==-1){
  3. cout <<"发送信息失败";}

整体视图:
在这里插入图片描述

recv函数

函数原型:

  1. intrecv(
  2. SOCKET s,//套接字char* buf,//接受数据的缓存区int len,//缓存区大小int flags //标志,一般填0,将消息拷贝到应用程序中,将内核中的数据删除,还可以填MSG_PEEK,只取数据,不从内核中删除数据,MSG_OOB:处理带外数据);//返回值:小于等于0都表示出错,大于0则表示接收成功的数据大小

使用:

  1. ret=recv(sockCli,buf,0xFF,0);if(ret <=0){
  2. cout <<"接受客户端数据失败";return-1;}

完整视图:
在这里插入图片描述

closesocket函数

  1. intclosesocket(
  2. SOCKET s //要关闭的socket);

该函数就是关闭不用的socket,释放资源

WSACleanup函数

无任何参数,直接调用即可

  1. WSACleanup();

按理说尽量在应用程序退出时都要进行清理,否则下次启动可能出现错误

修改后的代码视图:
在这里插入图片描述
完整代码:

  1. #define_WINSOCK_DEPRECATED_NO_WARNINGS#include<WinSock2.h>#pragmacomment(lib,"ws2_32")#include<iostream>usingnamespace std;intmain(){
  2. WSADATA data;int ret=WSAStartup(MAKEWORD(2,2),&data);if(ret){
  3. cout <<"初始化网络错误!"<< endl;WSACleanup();return-1;}
  4. SOCKET sock=socket(AF_INET,SOCK_STREAM,0);if(sock ==-1){
  5. cout <<"创建套接字失败";WSACleanup();return-1;}
  6. sockaddr_in addr;
  7. addr.sin_family = AF_INET;
  8. addr.sin_port =htons(9999);
  9. addr.sin_addr.S_un.S_addr =inet_addr("127.0.0.1");
  10. ret=bind(sock,(sockaddr*)&addr,sizeof(addr));if(ret ==-1){
  11. cout <<"绑定地址端口失败";WSACleanup();return-1;}
  12. ret=listen(sock,5);if(ret ==-1){
  13. cout <<"监听套接字失败";WSACleanup();return-1;}
  14. sockaddr addrCli;int len =sizeof(addrCli);
  15. SOCKET sockCli=accept(sock,&addrCli,&len);if(sockCli ==-1){
  16. cout <<"接收客户端连接失败";WSACleanup();return-1;}char buf[0xFF]="我是服务器";
  17. ret=send(sockCli, buf,strlen(buf),0);if(ret ==-1){
  18. cout <<"发送信息失败";WSACleanup();return-1;}
  19. ret=recv(sockCli,buf,0xFF,0);if(ret <=0){
  20. cout <<"接受客户端数据失败";WSACleanup();return-1;}WSACleanup();}

至此,一个最简单的windows服务器就写好了,可以简单执行一次发送数据和一次接受数据。

二、客户端

主要流程和函数:

  1. 初始化网络环境:WSAStartup
  2. 创建套接字:socket
  3. 连接服务器:connect
  4. 发送数据:send
  5. 接收数据:recv
  6. 清理网络环境:WSACleanup

其它三个函数与服务器一样,只是多出个connect函数,使用方法也与bind函数类似

connect函数

函数原型:

  1. intconnect(
  2. SOCKET s,//与服务器连接的socket
  3. sockaddr* name,//服务器的地址端口int namelen //上个参数结构体的长度);//返回值:-1失败,否则成功

使用方法:

  1. sockaddr_in addr;
  2. addr.sin_family = AF_INET;
  3. addr.sin_port =htons(9999);
  4. addr.sin_addr.S_un.S_addr =inet_addr("127.0.0.1");int ret =connect(sock,(sockaddr*)&addr,sizeof(addr));if(ret ==-1){
  5. cout <<"连接服务器失败"<< endl;return-1;}

完整代码视图:
在这里插入图片描述
完整代码:

  1. #define_WINSOCK_DEPRECATED_NO_WARNINGS#include<WinSock2.h>#include<iostream>#pragmacomment(lib,"ws2_32.lib")usingnamespace std;intmain(){
  2. WSADATA data;int ret =WSAStartup(MAKEWORD(2,2),&data);if(ret){
  3. cout <<"初始化网络错误!"<< endl;WSACleanup();return-1;}
  4. SOCKET sock =socket(AF_INET, SOCK_STREAM,0);
  5. sockaddr_in addr;
  6. addr.sin_family = AF_INET;
  7. addr.sin_port =htons(9999);
  8. addr.sin_addr.S_un.S_addr =inet_addr("127.0.0.1");int ret =connect(sock,(sockaddr*)&addr,sizeof(addr));if(ret ==-1){WSACleanup();
  9. cout <<"连接服务器失败"<< endl;return-1;}char buf[0xFF];
  10. ret=recv(sock,buf,sizeof(buf),0);if(ret <=0){WSACleanup();
  11. cout <<"接收服务器数据失败"<< endl;return-1;}
  12. cout <<"服务器:"<< buf << endl;
  13. ret=send(sock,buf,ret,0);//将接收到的数据发回服务器if(ret <=0){WSACleanup();
  14. cout <<"发送服务器数据失败"<< endl;return-1;}WSACleanup();}

三、其它网络相关函数

htons,ntohs等

这种函数名有固定的意义:

  • h:home
  • n:network
  • s:short
  • l:long

htons:意思就是本机字节序转到网络字节序,short类型的长度
ntohs:意思就是网络字节序转到本机字节序,short类型的长度

还有htonl,htonll,htonf等也是类似的意思

inet_addr,inet_ntoa

  • inet_addr:负责将我们平时看到的网络地址127.0.0.1等转化为网络字节序
  • inet_ntoa:负责将网络字节序还原为我们平时看到的字符串127.0.0.1等

使用方法:

  1. sockaddr_in addr;
  2. addr.sin_addr.S_un.S_addr =inet_addr("127.0.0.1");//将127.0.0.1转换为网络字节序char* c_IP =inet_ntoa(addr.sin_addr);//将网络字节序转换为127.0.0.1字符串

gethostbyname

通过域名获取ip地址,比如我们常见的www.baidu.com的ip地址是多少呢?就可以通过这个函数获取

使用方法:

  1. //获取主机ip
  2. HOSTENT* host =gethostbyname("www.baidu.com");//如获取网站IP地址,参数填写域名即可,不需加"http://"if(host ==NULL){returnfalse;}//转化为char*并拷贝返回
  3. cout <<inet_ntoa(*(in_addr*)*host->h_addr_list);

注意事项

这些函数都被微软定为不安全函数,想正常使用就必须在代码最前面定义宏:

  1. #define_WINSOCK_DEPRECATED_NO_WARNINGS
标签: c++ 网络

本文转载自: https://blog.csdn.net/weixin_50964512/article/details/123743421
版权归原作者 余识- 所有, 如有侵权,请联系我们删除。

“C/C++网络编程详解(Windows版)”的评论:

还没有评论