windows—socket函数整理
- 格式:docx
- 大小:18.05 KB
- 文档页数:4
socket 知识点总结Socket是计算机网络中的一个概念,用于描述在不同主机之间进行通信的一种方法。
本文将对Socket的基本概念、通信模型、常用函数以及应用场景进行总结。
一、Socket的基本概念Socket是一种通信机制,用于实现不同主机之间的数据传输。
它是对TCP/IP协议的封装,可以通过网络传输数据。
在网络编程中,Socket通常被称为“套接字”,它提供了一种接口,使得不同主机之间可以建立连接、发送和接收数据。
二、Socket的通信模型Socket的通信模型包括服务器-客户端模型和点对点模型。
1. 服务器-客户端模型:在这种模型中,服务器端首先创建一个Socket并绑定到指定的端口,然后监听客户端的连接请求。
当有客户端请求连接时,服务器端接受连接,并创建一个新的Socket与客户端进行通信。
通过这个新的Socket,服务器端可以向客户端发送数据,也可以接收客户端发送的数据。
2. 点对点模型:在这种模型中,两个主机之间可以直接进行通信,无需服务器的参与。
每个主机都可以创建一个Socket,并通过该Socket与对方建立连接,进行数据的发送和接收。
三、Socket的常用函数在网络编程中,我们可以使用一系列的Socket函数来实现不同的功能。
1. socket()函数:用于创建一个Socket。
它接受三个参数,分别是地址域(AF_INET表示IPv4)、类型(SOCK_STREAM表示面向连接的TCP套接字)和协议(通常为0,表示根据地址域和类型自动选择合适的协议)。
2. bind()函数:用于将一个Socket绑定到一个特定的地址和端口。
它接受两个参数,分别是Socket和一个地址结构体,包含了要绑定的IP地址和端口号。
3. listen()函数:用于将一个Socket设置为监听状态,等待客户端的连接请求。
它接受一个参数,表示等待连接的队列的最大长度。
4. accept()函数:用于接受客户端的连接请求,并创建一个新的Socket进行通信。
Socket 函数说明1.1 库函数综述1.1.1 套接字函数表 1.1 Windows Sockets 1.1 版本Berkeley Sockets函数函数名说明accept()确认外来连接,并将它与一个立即建立的数据套接字联系起来。
原始套接字返回到监听状态bind() 给未命名套接字赋一个本地名closesocket()从进程对象参考表中删去一个套接字,只有当SO_LINGER设置时才阻塞connect()在指定套接字上初始化连接getpeername() 获取与指定套接字连接的对等方的名字getsockname() 获取指定套接字的当前名字getsockopt() 获取与指定套接字相关的选项htonl() 将一个32位数从主机字节顺序转换为网络字节顺序htons() 将一个16 位数从主机字节顺序转换为网络字节顺序inet_addr() 将一个用网际标准点分表示法表示的字符串地址转换成网际地址值inet_ntoa() 将一个网际地址值转换成一个用点分十进制表示法表示的字符串地址ioctlsocket() 为套接字提供控制listen() 在指定套接字上监听外来连接ntohl() 将一个32位数从网络字节顺序转换为主机字节顺序ntohs() 将一个16 位数从网络字节顺序转换为主机字节顺序recv()从一个连接的套接字上接收数据recvfrom()从一个连接或未连接的套接字上接收数据select()执行多路同步I/Osend()给一个连接套接字发送数据sendto()给一个连接或未连接套接字发送数据setsockopt() 设置与指定套接字相关的选项shutdown() 关闭全双工连接的一部分socket() 建立一个通讯用的末端点,返回一个套接字注:标红函数作用在阻塞套接字上可以阻塞。
这些函数根据功能的不同可以分为如下几类:(1) 套接字函数。
此类函数包括socket(),bind(),getpeername(),getsockname()和closesocket(),它们主要完成创建,关闭套接字功能,以及对套接字命名与名字获取。
winsocket的基本概念和API函数勿在浅沙筑高楼。
在谈论TServerSocket等组件编写之前,这里先对Winsock中一些基本概念和API函数做一个简单的说明。
一、定址要通过Winsock建立通信,必须了解如何利用指定的协议为工作站定址。
Winsock 2引入了几个新的、与协议无关的函数,它们可和任何一个地址家族一起使用;但是大多数情况下,各协议家族都有自己的地址解析机制,要么通过一个函数,要么作为一个投给getsockopt的选项。
因为目前网络编程中用的最多最普遍的也许就是TCP/IP协议了,所以这里主要介绍此协议下的WinSock编程。
1、IP网际协议(Internet Protocol, IP)是一种用于互联网的网络协议,已经广为人知。
它可广泛用于大多数计算机操作系统上,也可用于大多数局域网LAN(比如办公室小型网络)和广域网WAN(比如说互联网)。
从它的设计看来,IP是一个无连接的协议,不能保证数据投递万无一失。
两个比它高级的协议(TCP和UDP)用于依赖IP协议的数据通信。
2、TCP面向连接的通信是通过“传输控制协议”(Transmission Control Protocol, TCP)来完成的。
TCP提供两台计算机之间的可靠无错的数据传输。
应用程序利用TCP进行通信时,源和目标之间会建立一个虚拟连接。
这个连接一旦建立,两台计算机之间就可以把数据当作一个双向字节流进行交换。
3、UDP无连接通信是通过“用户数据报协议”(User Datagram Protocol, UDP)来完成的。
UDP不保障可靠数据的传输,但能够向若干个目标发送数据,接收发自若干个源的数据。
简单地说,如果一个客户机向服务器发送数据,这一数据会立即发出,不管服务器是否已准备接收数据。
如果服务器收到了客户机的数据,它不会确认收到与否。
数据传输方法采用的是数据报。
TCP和UDP两者都利用IP来进行数据传输,一般称为TCP/IP和UDP/IP。
windowssocket函数详解windows socket函数详解 近期⼀直⽤第三⽅库写⽹络编程,反倒是遗忘了⽹络编程最底层的知识。
因⽽产⽣了整理Winsock函数库的想法。
以下知识点均来源于MSDN,本⼈只做翻译⼯作。
虽然很多前辈都做已了此类⼯作,但亲⼒亲为总记得清楚点。
0:函数库头⽂件1 #include <WinSock2.h>2#pragma comment(lib,"Ws2_32.lib ")1:WSAStartup 初始化Ws2_32.dll的函数description:The WSAStartup function initiates use of the Winsock DLL by a process. WSAStartup 函数⽤于初始化供进程调⽤的Winsock相关的dll。
1int WSAStartup(2 __in WORD wVersionRequested,3 __out LPWSADATA lpWSAData4 );Parameters wVersionRequestedThe highest version of Windows Sockets specification that the caller can use. The high-order byte specifies the minor version number; the low-order byte specifies the major version number.The current version of the Windows Sockets specification is version 2.2. The current Winsock DLL, Ws2_32.dll, supports applications that request any of the following versions of Windows Sockets specification,1.0、1.1、2.0、2.1、2.2。
socket函数详解1.socket函数⽤于创建⼀个新的socket,也就是向系统申请⼀个socket资源。
socket函数⽤户客户端和服务端。
//函数声明int socket(int domain, int type, int protocol);参数说明: domain:协议域,⼜称协议族(family)。
常⽤的协议族有AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域Socket)、AF_ROUTE等。
协议族决定了socket的地址类型,在通信中必须采⽤对应的地址,如AF_INET决定了要⽤ipv4地址(32位的)与端⼝号(16位的)的组合、AF_UNIX决定了要⽤⼀个绝对路径名作为地址。
type:指定socket类型。
常⽤的socket类型有SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等。
流式socket(SOCK_STREAM)是⼀种⾯向连接的socket,针对于⾯向连接的TCP服务应⽤。
数据报式socket(SOCK_DGRAM)是⼀种⽆连接的socket,对应于⽆连接的UDP服务应⽤。
protocol:指定协议。
常⽤协议有IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。
最后总结,第⼀个参数固定填AF_INET,第⼆个参数固定填SOCK_STREAM,第三个参数固定填0。
除⾮系统资料耗尽,socket函数⼀般不会返回失败。
返回值:成功则返回⼀个socket,失败返回-1,错误原因存于errno 中。
2.⼀个程序最多能打开1024个socket,当然该值由系统参数决定(因为linux⼀切皆⽂件,⽽⼀个程序能打开的最多⽂件数为1024,该值可以修改)。
常⽤socket函数详解常⽤socket函数详解关于socket函数,每个的意义和基本功能都知道,但每次使⽤都会去百度,参数到底是什么,返回值代表什么意义,就是说⽤的少,也记得不够精确。
每次都查半天,经常烦恼于此。
索性都弄得清楚、通透,并记录下来,⼀来便于⾃⼰记忆,再者以防⽇后查阅、回顾。
主要介绍:socket、bind、listen、connect、accept、send、sendto、recv、recvfrom、close、shutdown⽹络中的进程是通过socket来通信的,那什么是socket呢?socket起源于Unix,⽽Unix/Linux基本哲学之⼀就是“⼀切皆⽂件”,都可以⽤“打开open –> 读写write/read –> 关闭close”模式来操作。
我的理解就是Socket就是该模式的⼀个实现,socket即是⼀种特殊的⽂件。
其在linux和windows环境下的头⽂件主要是:#include<sys/socket.h>和#include<WinSock2.h>下⾯较为详细的介绍各个函数的使⽤⽅法,及返回值判断和处理。
另外,若想对函数调⽤后内核的详细动作过程,可参考UNIX⽹络编程第⼀卷或TCPIP详解第⼆卷。
1.socketint socket(int domain,int type, int protocol)_________________________返回值:⾮负描述符 – 成功,-1 - 出错其中:family指明了协议族/域,通常AF_INET、AF_INET6、AF_LOCAL等;type是套接⼝类型,主要SOCK_STREAM、SOCK_DGRAM、SOCK_RAW;protocol⼀般取为0。
成功时,返回⼀个⼩的⾮负整数值,与⽂件描述符类似。
对于windows环境下,在调⽤该函数之前需⾸先调⽤WSAStartup函数完成对Winsock服务的初始化,如#include<WinSock2.h>WSADATA wdata;if ( WSAStartup(MAKEWORD(2,2), &wdata) !=0 ){return INVALID_SOCKET;}后⾯即可调⽤socket函数,参数意义与linux环境⼀致。
Windows Socket学习笔记Socket(套接字)◆先看定义:typedef unsigned int u_int;typedef u_int SOCKET;◆Socket相当于进行网络通信两端的插座,只要对方的Socket和自己的Socket有通信联接,双方就可以发送和接收数据了。
其定义类似于文件句柄的定义。
◆Socket有五种不同的类型:1、流式套接字(stream socket)定义:#define SOCK_STREAM 1流式套接字提供了双向、有序的、无重复的以及无记录边界的数据流服务,适合处理大量数据。
它是面向联结的,必须建立数据传输链路,同时还必须对传输的数据进行验证,确保数据的准确性。
因此,系统开销较大。
2、数据报套接字(datagram socket)定义:#define SOCK_DGRAM 2数据报套接字也支持双向的数据流,但不保证传输数据的准确性,但保留了记录边界。
由于数据报套接字是无联接的,例如广播时的联接,所以并不保证接收端是否正在侦听。
数据报套接字传输效率比较高。
3、原始套接字(raw-protocol interface)定义:#define SOCK_RAW 3原始套接字保存了数据包中的完整IP头,前面两种套接字只能收到用户数据。
因此可以通过原始套接字对数据进行分析。
其它两种套接字不常用,这里就不介绍了。
◆Socket开发所必须需要的文件(以WinSock V2.0为例):头文件:Winsock2.h库文件:WS2_32.LIB动态库:W32_32.DLL一些重要的定义1、数据类型的基本定义:这个大家一看就懂。
typedef unsigned char u_char;typedef unsigned short u_short;typedef unsigned int u_int;typedef unsigned long u_long;2、网络地址的数据结构,有一个老的和一个新的的,请大家留意,如果想知道为什么,请发邮件给Bill Gate。
(⼗⼀)socket、connect、bind函数详解⼀、socket函数1、头⽂件:#include <sys/types.h> /* See NOTES */#include <sys/socket.h>2、函数原型:int socket(int domain, int type, int protocol);socket函数类似于open,⽤来打开⼀个⽹络连接,如果成功则返回⼀个⽹络⽂件描述符(int类型),之后我们操作这个⽹络连接都通过这个⽹络⽂件描述符。
dimain:域,⽹络域,⽹络地址范围(IPV4或IPV6等),也就是协议簇type:指定套接字类型:SOCK_STREAM(TCP⽹络)、SOCK_DGRAM(UDP)、SOCK_SEQPACKETprotocol:指定协议,如果指定0,表⽰使⽤默认的协议3、函数形参:3.1、domain:(域)AF_INET ipAF_INET6 ipv6AF_PACKET packet 低级数据包接⼝PF_PACKET 不懂,待了解PF_INET 待了解(AF开头的表⽰地址族,PF开头的表⽰协议族,协议族包含多个地址族,但是当前这种还从未实现,⽽在<sys/socket.h>中PF的值总是与AF的值相等的)3.2、type:(套接字类型):SOCK_RAW 原始套接字 ——>使⽤原始套接字时候调⽤,原始套接字也就是链路层协议SOCK_STREAM 字节流套接字 ——>提供顺序,可靠,双向,基于连接的字节流。
可以⽀持带外数据传输机制。
例如:TCP协议、FTP协议SOCK_DGRAM 数据报套接字 ——>⽀持数据报(⽆连接,不可靠的固定最⼤长度的消息)例如:UDP协议SOCK_SEQPACKET 有序分组套接字 ——>为固定最⼤长度的数据报提供有序,可靠,双向连接的数据传输路径; 消费者需要利⽤每个输⼊系统调⽤读取整个分组3.3、protocol(协议):IPPROTO_IP IP传输协议IPPROTO_TCP TCP传输协议IPPROTO_UDP UDP协议IPPROTO_SCTP SCTP传输协议IPPROTO_ICMP ICMP协议IPPROTO_IGMP IGMP协议⼀般情况下IPPROTO_TCP、IPPROTO_UDP、IPPROTO_ICMP协议⽤的最多,UDP协议protocol就取IPPROTO_UDP,TCP协议protocol就取IPPROTO_TCP;⼀般情况下,我们让protocol等于0就可以,系统会给它默认的协议。
socket主要函数介绍1. 基本套接字函数(1)socket函数原型socket(建⽴⼀个socket⽂件描述符)所需头⽂件#include <sys/types.h>#include <sys/socket.h>函数说明建⽴⼀个socket⽂件描述符函数原型int socket(int domain, int type, int protocol)函数传⼊值domainAF_INET:IPv4协议AF_INET6:IPv6协议AF_LOCAL:Unix域协议AF_ROUTE:路由套接⼝AF_KEY:密钥套接⼝typeSOCKET_STREAM:双向可靠数据流,对应TCPSOCKET_DGRAM:双向不可靠数据报,对应UDPSOCKET_RAW:提供传输层以下的协议,可以访问内部⽹络接⼝,例如接收和发送ICMP报⽂protocoltype为SOCKET_RAW时需要设置此值说明协议类型,其他类型设置为0即可函数返回值成功:socket⽂件描述符失败:-1,失败原因存于error中表18-1列出了当进⾏socket调⽤时,中协议簇(domain)与类型(type)可能产⽣的组合。
表18-1 socket中协议簇(domain)与类型(type)组合表AF_INETAF_INET6AF_LOCALAF_ROUTEAF_KEYSOCK_STREAMTCPYesSOCK_DGRAMUDPUDPYesSOCK_RAWIPv4IPv6YesYes(2)bind函数原型bind(将⼀个本地协议地址与socket⽂件描述符联系起来)所需头⽂件#include <sys/types.h>#include <sys/socket.h>函数说明将⼀个协议地址与socket⽂件描述符联系起来函数原型int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)函数传⼊值sockfdsocket⽂件描述符addrmy_addr指向sockaddr结构,该结构中包含IP地址和端⼝等信息addrlensockaddr结构的⼤⼩,可设置为sizeof(struct sockaddr)函数返回值成功:0失败:-1,失败原因存于error中利⽤bind函数绑定地址时,可以指定IP地址和端⼝号,也可以指定其中之⼀,甚⾄⼀个也不指定。
1、recvfromrecvfrom函数(经socket接收数据):函数原型:ssize_t recvfrom(int sockfd,void *buf,int len,unsigned int flags, struct sockaddr *from,socket_t *fromlen);ssize_t 相当于int,socket_t 相当于int ,这里用这个名字为的是提高代码的自说明性。
相关函数recv,recvmsg,send,sendto,socket函数说明:recv()用来接收远程主机经指定的socket传来的数据,并把数据传到由参数buf指向的内存空间,参数len为可接收数据的最大长度.参数flags一般设0,其他数值定义参考recv().参数from用来指定欲传送的网络地址,结构sockaddr请参考bind()函数.参数fromlen为sockaddr的结构长度.返回值:成功则返回接收到的字符数,失败返回-1.错误代码EBADF 参数s非合法的socket处理代码EFAULT 参数中有一指针指向无法存取的内存空间。
ENOTSOCK 参数s为一文件描述词,非socket。
EINTR 被信号所中断。
EAGAIN 此动作会令进程阻断,但参数s的socket为不可阻断。
ENOBUFS 系统的缓冲内存不足ENOMEM 核心内存不足EINVAL 传给系统调用的参数不正确。
范例/*利用socket的UDP client此程序会连线UDP server,并将键盘输入的字符串传给server。
UDP server 范例请参考sendto()。
*/#include<sys/stat.h>#include<fcntl.h>#include<unistd.h>#include<sys/typs.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#define PORT 2345#define SERVER_IP “127.0.0.1”main(){int s,len;struct sockaddr_in addr;int addr_len =sizeof(struct sockaddr_in);char buffer[256];/* 建立socket*/if((s = socket(AF_INET,SOCK_DGRAM,0))<0){perror(“socket”);exit(1);}/* 填写sockaddr_in*/bzero(&addr,sizeof(addr));addr.sin_family = AF_INET;addr.sin_port = htons(PORT);addr.sin_addr.s_addr = inet_addr(SERVER_IP);while(1){bzero(buffer,sizeof(buffer));/* 从标准输入设备取得字符串*/len =read(STDIN_FILENO,buffer,sizeof(buffer));/* 将字符串传送给server端*/sendto(s,buffer,len,0,(struct sockaddr *)&addr,addr_len);/* 接收server端返回的字符串*/len = recvfrom(s,buffer,sizeof(buffer),0,(struct sockaddr *)&addr,&addr_len); printf(“receive: %s”,buffer);}}执行(先执行udp server 再执行udp client)hello /*从键盘输入字符串*/receive: hello /*server端返回来的字符串*/2、Socket 错误一览表关键词:Socket错误 TCP/IP Windows VC最近程序出现几次Socket 错误, 为了便于差错.. 搜了一些贴在这里..出现网络联机错误Socket error #11001表示您的计算机无法连上服务器,请检查您的Proxy设定以及Proxy相关账号,或暂时取消您防毒软件的「个人防火墙」。
socket函数的三个参数Socket函数是在网络编程中常用的函数之一,它用于在主机之间建立通信连接。
在使用Socket函数时,我们需要传递三个参数,分别是地址族(Address Family)、套接字类型(Socket Type)和协议(Protocol)。
这三个参数决定了Socket函数的行为和功能,下面将详细介绍每个参数的作用和用法。
一、地址族(Address Family)地址族是指网络中主机的地址类型,常用的地址族有IPv4和IPv6。
在Socket函数中,我们可以使用常量AF_INET表示IPv4地址族,使用常量AF_INET6表示IPv6地址族。
地址族的选择取决于网络环境和需求,例如在IPv4网络中,我们需要使用AF_INET来创建套接字。
二、套接字类型(Socket Type)套接字类型是指套接字的工作方式和特性,常用的套接字类型有流套接字(SOCK_STREAM)和数据报套接字(SOCK_DGRAM)。
流套接字提供面向连接的可靠通信,适用于需要传输大量数据且要求可靠性的场景。
数据报套接字则是无连接的,适用于短小的消息传输。
在Socket函数中,我们可以使用常量SOCK_STREAM来创建流套接字,使用常量SOCK_DGRAM来创建数据报套接字。
三、协议(Protocol)协议是指数据在网络中传输时的规则和约定,常用的协议有TCP和UDP。
TCP协议提供可靠的、面向连接的通信,适用于需要确保数据完整性和顺序的场景。
UDP协议则是无连接的,不保证数据的可靠性和顺序。
在Socket函数中,我们可以使用常量IPPROTO_TCP来创建基于TCP协议的套接字,使用常量IPPROTO_UDP来创建基于UDP 协议的套接字。
在使用Socket函数时,我们需要根据具体的需求选择合适的地址族、套接字类型和协议。
例如,如果我们需要在IPv4网络中建立可靠的连接,并传输大量数据,可以使用如下代码创建一个TCP套接字:```int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);```这个代码中,socket函数的第一个参数指定了地址族为IPv4,第二个参数指定了套接字类型为流套接字,第三个参数指定了协议为TCP。
Windows SOCKET编程第一章序言我写这个专题的目的,一方面是为了通过对网络编程再一次系统的总结,提高自己的网络编程水平,特别是Windows下的网络编程水平。
同时,我也希望,能为众多初学网络编程的人提供一点帮助,因为我开始学习网络编程的时候,能找到的资料就很少。
当然,花钱可以买到翻译版本的书:)首先向大家推荐一本很好的参考书,Network Programming for Microsoft Windows 2nd,初学网络编程的时候我还不知道有这样一本好书,只是上各大论坛把能找到的网络编程方面的文章和代码下载下来,然后自己研究。
后来看到别人推荐这一本书,下载了一个,看了感觉非常好,里面的内容写得很规范,条理也很清楚,英文好的朋友可以直接阅读,不然就只好去弄一本翻译好的来研究了。
我试着从Windows编程的基础开始,一直到探索建立高性能的网络应用程序。
我说过,我并不是以高手的身份写这本书,而是以和大家一起学习的心态学习网络编程,写书只是让自己的思路更清晰,以后还可以翻阅。
所以,我不保证书中所有的内容都是绝对正确和标准的,有不妥的地方,还希望高手批评指正。
这本书是完全免费的,读者可以任意使用书中的代码。
但是如果需要转载,请注明原作者和出处。
如果有商业运作的需求,请直接和我联系。
第二章Windows网络编程基础这本书主要探索Windows网络编程,开发平台是Windows 2000 和Visual C++.NET,从一个合格的C++程序员到网络编程高手,还是需要花不少功夫,至少我认为写一个聊天程序很简单,而要写一个能同时响应成千上万用户的高性能网络程序,的确不容易。
这篇文章所介绍的方法也并不是能直接应用于每一个具体的应用程序,只能作为学习的参考资料。
开发高性能网络游戏恐怕是促使很多程序员研究网络编程的原因(包括我),现在的大型网络游戏对同时在线人数的要求比较高,真正的项目往往采取多个服务器(组)负荷分担的方式工作,我将首先把注意力放到单个服务器的情况。
第七章Windows Sockets 2扩展库函数简要参考7.1 WSAAccept()简述:根据条件函数的返回值有条件地接受连接,同时(可选地)创建和/或加入一个套接口组。
SOCKET WSAAPI WSAAccept ( SOCKET s, structsockaddr FAR * addr, int FAR * addrlen,LPCONDITIONPROC lpfnCondition, DWORDdwCallbackData );s:标识一个套接口的描述字,该套接口在listen()后监听连接。
addr:(可选)指针,指向存放通讯层所知的连接实体地址的缓冲区。
addr参数的具体格式由套接口创建时产生的地址族决定。
addrlen:(可选)指针,指向存放addr地址长度的整形数。
lpfnCondition:(可选的)用户提供的条件函数的进程实例地址。
该函数根据参数传入的调用者信息作出接受或拒绝的决定,并通过给结果参数赋予特定的值来(可选地)创建和/或加入一个套接口组。
dwCallbackData:作为条件函数参数返回给应用程序的回调数据。
WinSock不分析该参数。
返回值:若无错误发生,WSAAccept()函数返回所接受套接口的描述字。
否则的话,将返回INVALID_SOCKET错误,应用程序可通过WSAGetLastError()来获取相应的错误代码。
addrlen参数引用的整形数初始时包含了addr参数所指向的空间数,在调用返回时包含了返回地址的实际长度。
错误代码:WSANOTINITIALISED 在调用本API之前应成功调用WSAStartup()。
WSAECONNREFUSED 根据条件函数的返回值(CF_REJECT)强制拒绝连接请求。
WSAENETDOWN 网络子系统失效。
WSAEFAULT addrlen参数太小(小于sockaddr结构的大小),或者lpfnCondition 并不是用户空间的一部分。
WSAStartup函数原型注释成员返回值错误代码WSAStartup函数原型注释成员返回值错误代码展开编辑本段WSAStartup简介WSAStarup,即WSA(Windows SocKNDs Asynchronous,Windows套接字异步)的启动命令。
是Windows下的网络编程接口软件 Winsock1 或 Winsock2 里面的一个命令(Ps:Winsock 是由Unix下的BSD Socket发展而来,是一个与网络协议无关的编程接口)。
详细说明为了在应用程序当中调用任何一个Winsock API函数,首先第一件事情就是必须通过WSAStartup函数完成对Winsock服务的初始化,因此需要调用WSAStartup函数。
使用Socket的程序在使用Socket之前必须调用WSAStartup 函数。
该函数的第一个参数指明程序请求使用的Socket版本,其中高位字节指明副版本、低位字节指明主版本;操作系统利用第二个参数返回请求的Socket的版本信息。
当一个应用程序调用WSAStartup函数时,操作系统根据请求的Socket版本来搜索相应的Socket库,然后绑定找到的Socket库到该应用程序中。
以后应用程序就可以调用所请求的Socket库中的其它Socket函数了。
编辑本段函数原型#includeint PASCAL FAR WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData );wVersionRequested Windows Sockets API提供的调用方可使用的最高版本号。
高位字节指出副版本(修正)号,低位字节指明主版本号。
lpWSAData 指向WSADATA数据结构的指针,用来接收Windows Sockets实现的细节。
编辑本段注释本函数必须是应用程序或DLL调用的第一个Windows Sockets函数。
Windows Socket 1.1库函数大全[]Windows Socket 1.1库函数参考本章以字母顺序列出了套接口库函数,并介绍了技术细节。
使用任一库函数时应在程序中包含WINSOCK.H头文件。
在附录 A.2中还列出了一些与BERKELEY兼容的头文件。
这些头文件只起到兼容性的作用,它们都包含了WINSOCK.H头文件,WINDOWS.H头文件也是必需的,但WINSOCK.H会视需要包含这一头文件。
5.1.1 accept()简述:在一个套接口接受一个连接。
#include <winsock.h>SOCKET PASCAL FAR accept( SOCKET s, struct sockaddr FAR* addr,int FAR* addrlen);s:套接口描述字,该套接口在listen()后监听连接。
addr:(可选)指针,指向一缓冲区,其中接收为通讯层所知的连接实体的地址。
Addr参数的实际格式由套接口创建时所产生的地址族确定。
addrlen:(可选)指针,指向存有addr地址长度的整形数。
注释:本函数从s的等待连接队列中抽取第一个连接,创建一个与s同类的新的套接口并返回句柄。
如果队列中无等待连接,且套接口为非阻塞方式,则accept()阻塞调用进程直至新的连接出现。
如果套接口为非阻塞方式且队列中等待连接,则accept()返回一错误代码。
已接受连接的套接口不能用于接受新的连接,原套接口仍保持开放。
addr参数为一个返回参数,其中填写的是为通讯层所知的连接实体地址。
addr参数的实际格式由通讯时产生的地址族确定。
ad drlen参数也是一个返回参数,在调用时初始化为addr 所指的地址空间;在调用结束时它包含了实际返回的地址的长度(用字节数表示)。
该函数与SOCK_STREAM类型的面向连接的套接口一起使用。
如果addr与addrlen中有一个为零NULL ,将不返回所接受的套接口远程地址的任何信息。
Select模型
Select模型是Windows sockets中最常见的IO模型。
它利用select函数实现IO 管理。
通过对select函数的调用,应用程序可以判断套接字是否存在数据、能否向该套接字写入数据。
如:在调用recv函数之前,先调用select函数,如果系统没有可读数据那么select函数就会阻塞在这里。
当系统存在可读或可写数据时,select函数返回,就可以调用recv函数接收数据了。
可以看出使用select模型,需要两次调用函数。
第一次调用select函数第二次socket API。
使用该模式的好处是:可以等待多个套接字。
select函数中需要三个fd_set结构:
一:准备接收数据的套接字集合,即可读性集合。
二:准备发送数据的套接字集合,即可写性集合。
在select函数返回时,会在fd_set结构中,填入相应的套接字。
readfds数组将包括满足以下条件的套接字:
1:有数据可读。
此时在此套接字上调用recv,立即收到对方的数据。
2:连接已经关闭、重设或终止。
3:正在请求建立连接的套接字。
此时调用accept函数会成功。
writefds数组包含满足下列条件的套接字:
1:有数据可以发出。
此时在此套接字上调用send,可以向对方发送数据。
2:调用connect函数,并连接成功的套接字。
exceptfds数组将包括满足下列条件的套接字:
1:调用connection函数,但连接失败的套接字。
2:有带外(out of band)数据可读。
select函数的使用:
在调用select函数对套接字进行监视之前,必须将要监视的套接字分配给上述三个数组中的一个。
然后调用select函数,再次判断需要监视的套接字是否还在原来的集合中。
就可以知道该集合是否正在发生IO操作。
例如:应用程序想要判断某个套接字是否存在可读的数据,需要进行如下步骤:1:将该套接字加入到readfds集合。
2:以readfds作为第二个参数调用select函数。
3:当select函数返回时,应用程序判断该套接字是否仍然存在于readfds集合。
4:如果该套接字存在与readfds集合,则表明该套接字可读。
此时就可以调用recv 函数接收数据。
否则,该套接字不可读。
在调用select函数时,readfds、writefds和exceptfds三个参数至少有一个为非空。
并且在该非空的参数中,必须至少包含一个套接字。
否则select函数将没有任何套接字可以等待。
timeval结构体用于定义select的等待时间。
structure timeval
{
long tv_sec;//秒。
long tv_usec;//毫秒。
};
当timeval为空指针时,select会一直等待,直到有符合条件的套接字时才返回。
当tv_sec和tv_usec之和为0时,无论是否有符合条件的套接字,select都会立即返回。
当tv_sec和tv_usec之和为非0时,如果在等待的时间内有套接字满足条件,则该函数将返回符合条件的套接字。
如果在等待的时间内没有套接字满足设置的条件,则select会在时间用完时返回,并且返回值为0。
为了方便使用,windows sockets提供了下列宏,用来对fd_set进行一系列操作。
使用以下宏可以使编程工作简化。
FD_CLR(s,*set);从set集合中删除s套接字。
FD_ISSET(s,*set);检查s是否为set集合的成员。
FD_SET(s,*set);将套接字加入到set集合中。
FD_ZERO(*set);将set集合初始化为空集合。
在开发Windows sockets应用程序时,通过下面的步骤,可以完成对套接字的可读写判断:
1:使用FD_ZERO初始化套接字集合。
如FD_ZERO(&readfds);
2:使用FD_SET将某套接字放到readfds内。
如:
FD_SET(s,&readfds);
3:以readfds为第二个参数调用select函数。
select在返回时会返回所有fd_set集合中套接字的总个数,并对每个集合进行相应的更新。
将满足条件的套接字放在相应的集合中。
4:使用FD_ISSET判断s是否还在某个集合中。
如:
FD_ISSET(s,&readfds);
5:调用相应的Windows socket api 对某套接字进行操作。
select返回后会修改每个fd_set结构。
删除不存在的或没有完成IO操作的套接字。
这也正是在第四步中可以使用FD_ISSET来判断一个套接字是否仍在集合中的原因。
看例子,该例演示了一个服务器程序使用select模型管理套接字。
[cpp]
SOCKET listenSocket;
[cpp]
SOCKET acceptSocket;
FD_SET socketSet;
FD_SET writeSet;
FD_SET readSet;
FD_ZERO(&socketSet);
FD_SET(listenSocket,&socketSet);
while(true)
{
FD_ZERO(&readSet);
FD_ZERO(&writeSet);
readSet=socketSet;
writeSet=socketSet;
//同时检查套接字的可读可写性。
int ret=select(0,&readSet,&writeSet,NULL,NULL);
if(ret==SOCKET_ERROR)
{
return false;
}
sockaddr_in addr;
int len=sizeof(addr);
//是否存在客户端的连接请求。
if(FD_ISSET(listenSocket,&readSet))//在readset中会返回已经调用过listen的套接字。
{
acceptSocket=accept(listenSocket,(sockaddr*)&addr,&len);
if(acceptSocket==INVALID_SOCKET)
{
return false;
}
else
{
FD_SET(acceptSocket,&socketSet);
}
}
for(int i=0;i<socketSet.fd_count;i++)
{
if(FD_ISSET(socketSet.fd_array[i],&readSet))
{
//调用recv,接收数据。
}
if(FD_ISSET(socketSet.fd_array[i]),&writeSet)
{
//调用send,发送数据。
}
}
}。