Windows网络编程(基础篇1)
Windows网络编程(基础篇1)
- Winsock是一种网络编程接口,不是协议。
- 除了WSAStartup、WSACleanup、WSARecvEx、WSAGetLastError属于Winsocket1.1规范函数外,凡是有前缀WSA的,都是在Winsock 2 中更新或者增添的一个新的API函数。
一、Winsock初始化
包含头文件winsock2.h,链接库WS2_32
include <winsock2.h>#pragma comment(lib,"WS2_32")
使用Winsock的应用都必须加载合适的Winsock DLL版本,否则返回SOCKET_ERROR。使用WSAStartup加载,最后需要调用WSACleanup释放Winsock分配的资源。
int WSAStartup(_In_ WORD wVersionRequested,_Out_ LPWSADATA lpWSAData );
- wVersionRequested:版本号,高阶字节指定小版本号,低位字节指定主版本。
- lpWSAData 指向WSADATA数据结构的,接收Windows Sockets实现细节。
WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData);//成功返回0
MAKEWORD:创建一个无符号16位整形,通过连接两个给定的无符号参数,也就是将(2,2)放入wVersionRequested中。
WSAGetLastError();//返回调用winsock函数发生的错误代码 WSACleanup();//程序结束时,需要调用释放资源
二、SOCKADDR_IN简介
SOCKADDR_IN:用来指定IP地址和端口信息。
typedef struct sockaddr_in {short sin_family; //The address family for the transport address,must AF_INETUSHORT sin_port; //port numberIN_ADDR sin_addr; // IPv4 transport addressCHAR sin_zero[8]; //Reserved(预留) for system use } SOCKADDR_IN, *PSOCKADDR_IN;
inet_pton 转换字符串到网络地址。将“点分十进制” -> “二进制整数”(inet_addr已弃用)
//m_HostGroup.sin_addr.s_addr = inet_addr(strGroupIP);//代替方法如下:
inet_pton(AF_INET, strGroupIP, (void*)&m_HostGroup.sin_addr.s_addr);
INT WSAAPI InetPton(_In_ INT Family, // AF_INET and AF_INET6._In_ PCTSTR pszAddrString, //待转换的地址,IPV4 或 IPV6_Out_ PVOID pAddrBuf //转换后的(IPV4:IN_ADDR,IPV6: IN6_ADDR );
htons 将整型变量从主机字节顺序转变成网络字节顺序
u_short WSAAPI htons(_In_ u_short hostshort);
ntohl 将网络字节顺序转换成主机字节顺序
u_long WSAAPI ntohl(_In_ u_long netlong);
- 创建SOCKADDR_IN结构示例:
SOCKADDR_IN sin; WORD Port=80; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(Port); inet_pton(AF_INET, "192.168.1.1", (void*)&sin.sin_addr.S_un.S_addr);
三、套接字通信(TCP)
创建套接字函数:socket、WSASocket;
SOCKET WSAAPI socket(_In_ int af, //指定协议族 AF_INET、AF_INET6、AF_LOCAL等_In_ int type, //指定Socket类型 (TCP)SOCK_STREAM、(UDP)SOCK_DGRAM、SOCK_RAW等_In_ int protocol //指定协议 IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP等 );
创建套接字后,就必须将套接字绑定到一个已知地址上:bind;
int bind(_In_ SOCKET s, //待连接的套接字_In_ const struct sockaddr *name, //地址缓冲区(sockaddr *)sockaddr_in_In_ int namelen //name大小 );
将套接字置入监听模式:listen;(bind只是将套接字和指定地址关联,listen指示套接字等候连接)
int listen(_In_ SOCKET s, //待监听的套接字_In_ int backlog //等待连接队列的最大长度 );
有客户端连接到达时,接收一个连接:accept ;
SOCKET accept(_In_ SOCKET s, //正在监听的套接字_Out_ struct sockaddr *addr, //连接者的地址_Inout_ int *addrlen //指向存有addr地址长度的整数 );
客户端通过套接字连接到服务端:connect;
int connect(_In_ SOCKET s, _In_ const struct sockaddr *name,_In_ int namelen );
服务端示例:
#include<winsock2.h>#pragma comment(lib,"WS2_32")int main(void) { WSADATA wsaData; if (::WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {return 0; } SOCKET ListeningSocket; SOCKET NewConnetction; SOCKADDR_IN ServerAddr; SOCKADDR_IN ClientAddr; int Port = 5150;//创建一个套接字来监听客户端连接 ListeningSocket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); ServerAddr.sin_family = AF_INET; ServerAddr.sin_port = htons(Port); ServerAddr.sin_addr.S_un.S_addr = INADDR_ANY;//用bind将套接字信息和地址信息绑定 ::bind(ListeningSocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr));//监听客户连接,限制5个 ::listen(ListeningSocket, 5);//连接到达时,接受一个新连接 int ClientaddrLen; NewConnetction = ::accept(ListeningSocket, (SOCKADDR*)&ClientAddr, &ClientaddrLen);//此时在这些套接字上可以做: //1.在ListeningSocket上再次调用accept,等待更多的连接。2.在NewConnection上完成数据收发。//关闭套接字 closesocket(NewConnetction); closesocket(ListeningSocket);WSACleanup(); return 1; }
客户端示例:
#include<winsock2.h>#include<Ws2tcpip.h>#pragma comment(lib,"WS2_32")int main(void) { WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {return 0; } SOCKET S; SOCKADDR_IN ServerAddr; int Port = 5150;//创建一个套接字来建立客户端连接 S = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); ServerAddr.sin_family = AF_INET; ServerAddr.sin_port = htons(Port); inet_pton(AF_INET, "192.168.1.1", (void*)&ServerAddr.sin_addr.S_un.S_addr); connect(S, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr));//关闭套接字 closesocket(S); WSACleanup(); return 1; }
为什么客户端不用bind
- 无连接的socket的客户端和服务端以及面向连接socket的服务端通过调用bind函数来配置本地信息。使用bind函数时,通过将my_addr.sin_port置为0,函数会自动为你选择一个未占用的端口来使用。
- 有连接的socket客户端通过调用Connect函数在socket数据结构中保存本地和远端信息,无须调用bind(),因为这种情况下只需知道目的机器的IP地址,而客户通过哪个端口与服务器建立连接并不需要关心,socket执行体为你的程序自动选择一个未被占用的端口,并通知你的程序数据什么时候打开端口。
- 服务端进程bind IP地址:目的是限制了服务端进程创建的socket只接受那些目的地为此IP地址的客户链接
1.需要在建连前就知道端口的话,需要 bind
2.需要通过指定的端口来通讯的话,需要 bind
四:数据传输
要在已经建立的套接字上发送数据,可以用send和WSASend。接收数据可以用recv和WSARecv。
int send(_In_ SOCKET s, //是一个已经建立了连接,用于发送数据的套接字_In_ const char *buf, //指向即将发送数据的缓冲区_In_ int len, //缓冲区内的字符数_In_ int flags //调用执行方式 );//如果成功,返回的是发送的字节数,否则返回SOCKET_ERROR
int WSASend(_In_ SOCKET s,_In_ LPWSABUF lpBuffers,_In_ DWORD dwBufferCount,_Out_ LPDWORD lpNumberOfBytesSent,_In_ DWORD dwFlags,_In_ LPWSAOVERLAPPED lpOverlapped,_In_ LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine );
char sendbuff[2048];int nBytes=2048; sendbuff=******;
ret=send(s,sendbuff,nBytes,0);
对于send函数而言,可能返回已发出的字节数少于给定的字节数。因为对于每个收发数据的套接字来说,系统都为他们分配了相当充足的缓冲区空间,所以返回值ret变量将被设为已发送的字节数。在发送数据时,内部缓冲区都会将数据一致保留到可以将它发到线上为之。比如,传输大量的数据可以领缓冲区快速填满。同时,对TCP/IP来说,还有一个窗口大小的问题。接收端会对窗口大小进行调节,以指示它可以接收多少数据。如果有大量数据涌入接收端,接收端就会将窗口大小设为0,为挂起数据做好准备。对发送端来说,这样会强制它在收到一个新的大于0的窗口大小之前,不得再发送数据。在使用send调用时,缓冲区可能只能容纳1024字节,这时,便有必要重新提交剩下的1024字节。
char sendbuff[2018]; int nBytes=2048, nLeft, idx; nLeft=nBytes; idx=0; while(nLeft>0){ret=send(s,&sendbuff[idx],nLeft,0);if(ret==SOCKET_ERROR){//error}nLeft-=ret;idx+=ret;}
在已经建立连接的套接字上接受数据的传入,可以使用recv和WSARecv。
int recv(_In_ SOCKET s,_Out_ char *buf,_In_ int len,_In_ int flags );
int WSARecv(_In_ SOCKET s,_Inout_ LPWSABUF lpBuffers,_In_ DWORD dwBufferCount,_Out_ LPDWORD lpNumberOfBytesRecvd,_Inout_ LPDWORD lpFlags,_In_ LPWSAOVERLAPPED lpOverlapped,_In_ LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine );
流套接字是一个不间断的数据流,在读取它时,应用程序通常不会关心应该读多少数据。如果所有消息长度都一样,则处理要简单,比如读取512字节。
char recvbuff[1024]; int ret, nLeft, idx; nLeft=512; idx=0; while(nLeft>0){ret=recv(s,&recvbuff[idx],nleft,0);if(ret==SOCKET_ERROR){//error}idx+=ret;nLeft-=ret;}
如果消息长度不同,就必须要利用自己的协议来通知接收端,让它知道即将到来的消息长度是多少。比如,写入接收端的前4个字节总是整数,用来标记即将到来的消息长度。
中断连接
一旦完成了套接字连接,就必须将它关掉,并释放关联到那个套接字句柄的所有资源,执行closesocket即可。但是,closesocket可能带来的负面影响就是导致数据丢失。鉴于此,在调用closesocket函数之前,利用shutdown函数从容中止连接。
int shutdown(_In_ SOCKET s,_In_ int how //SD_RECEIVE,SD_SEND, SD_BOTH );//关闭一个套接字
对closesocket调用释放的套接字描述符,如果再次利用该套接字就会调用失败。如果没有对改套接字的其他引用,那么所有与套接字描述符相关的资源都会被释放,包括丢弃所有队列中的数据。
Windows网络编程(基础篇1)相关推荐
- 万物互联之~网络编程基础篇
入门篇¶ 官方文档:https://docs.python.org/3/library/ipc.html(进程间通信和网络) 实例代码:https://github.com/lotapp/BaseCo ...
- Java网络编程基础_Java网络编程基础篇
一.前言 网络通讯在系统交互中是必不可少的一部分,无论是面试还是工作中都是绕不过去的一部分,本节我们来谈谈Java网络编程中的一些知识,本chat内容如下: 网络通讯基础知识,剖析网络通讯的本质和需要 ...
- Windows网络编程(一)基础
Table of Contents 准备工作 socket C/S模式 源代码 服务端 客户端 源码分析 数据传输 关闭连接 符号解释 WSAStartup sin_family sin_port i ...
- Windows黑客编程基础
俗话说:"万事开头难",编程也不例外,初学者如何入门关键要有一份正确的理论作指 导,下面的这篇文章虽不能说是至理名言,但我相信通过作者细腻的分析.讲解和引导, 定能给初学者起到启蒙 ...
- python网络编程证书_《Python网络编程基础》笔记
python网络编程基础 ================== Author: lujun9972 Date: 2013-03-08 22:29:20 CST Table of Contents == ...
- [内核编程] 内核环境及其特殊性,驱动编程基础篇
[内核编程] 内核环境及其特殊性,驱动编程基础篇 在学习汉江独钓一书后,打算总结一下内核编程应该注意的事项,以及有关的一些基础知识.第一次接触内核编程,还真是很生疏,很多东西不能一下马上消化.这里做 ...
- java 编程原理_Java网络编程 -- 网络编程基础原理
Hello,今天记录下 Java网络编程 --> 网络编程基础原理. 一起学习,一起进步.继续沉淀,慢慢强大.希望这文章对您有帮助.若有写的不好的地方,欢迎评论给建议哈! 初写博客不久,我是杨展 ...
- Python3——网络编程基础
Python3--网络编程基础 基础知识参考: https://blog.csdn.net/wqx521/article/details/51037048 https://blog.csdn.net/ ...
- 多实例多进程网络编程PHP,php socket网络编程基础知识(四):多进程
标签:status 传递 windows 返回 修改 队列 _for 响应 关联 说明 php在web编程时是不需要考虑多进程的,但整个php流程是涉及到多进程的,只不 ...
- Windows驱动编程基础教程
前言 本书非常适合熟悉Windows应用编程的读者转向驱动开发.所有的内容都从最基础的编程方法入手.介绍相关的内核API,然后举出示范的例子.这本书只有不到70页,是一本非常精简的小册子.所以 ...
最新文章
- spring boot初学习的数据库依赖
- Android -- 多线程下载
- 计算机硬件2部件指的是什么,计算机基础-2.计算机硬件基础.doc
- Springboot集成cache的key生成策略
- hdu 4091 线性规划
- 【MATLAB统计分析与应用100例】案例003:matlab调用smooth函数进行加噪数据的平滑处理
- php 5.6 文档,文件存储 | 进阶系列 | Laravel 5.6 中文文档
- 调试寄存器:Debug Register
- mapreduce程序调用各个类的功能
- 计算机毕业设计Java在线小说系统(源码+系统+mysql数据库+Lw文档)
- cad怎么画立体图形教学_立体图形怎么画步骤 找CAD图形中心点的方法步骤图
- 详解MOVE PROTOCOL的测试版,让健康运动如影随形
- Contrast Preserving Decolorization
- SSM框架搭建简单实例
- QT-3-基本组件2
- flex 垂直方向 两端对齐
- ionic升华过程8-cordova插件+mui小案例
- 为远控添加功能[1]
- Premiere插件大全介绍知羽,意匠,爱维,
- 基于Simulink的永磁同步电机仿真控制系统
热门文章
- 软考中级考试经验分享-系统集成项目管理工程师
- android模拟器命令行,夜神安卓模拟器命令行整理贴
- mnist数据集下载——mnist数据集提供百度网盘下载地址
- 父与子一起学python3_父与子的编程之旅(与小卡特一起学Python第3版全彩印刷)/图灵程序设计丛书...
- java dump 工具_Java内存Dump文件查看和分析工具介绍
- Adobe Acrobat Reader离线安装包下载
- hit网络安全实验报告
- flyMcu给STM32串口烧录失败踩坑、总结及注意事项
- ngrok跟小米球的使用
- xml样本标签转txt