Winsock总结

1.Winsock的启动和终止

启动

调用int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData)函数对Winsock DLL进行初始化,参数说明如下:

wVersionRequested:用于指定要加载的Winsock库版本,高四位是副版本号,第四位是主版本号;

lpWSAData:指定了加载的库版本的相关信息,其格式如下

 

#define WSADESCRIPTION_LEN      256
#define WSASYS_STATUS_LEN       128

typedef struct WSAData {
        WORD                    wVersion;
        WORD                    wHighVersion;
#ifdef _WIN64
        unsigned short          iMaxSockets;
        unsigned short          iMaxUdpDg;
        char FAR *              lpVendorInfo;
        char                    szDescription[WSADESCRIPTION_LEN+1];
        char                    szSystemStatus[WSASYS_STATUS_LEN+1];
#else
        char                    szDescription[WSADESCRIPTION_LEN+1];
        char                    szSystemStatus[WSASYS_STATUS_LEN+1];
        unsigned short          iMaxSockets;
        unsigned short          iMaxUdpDg;
        char FAR *              lpVendorInfo;
#endif
} WSADATA;

typedef WSADATA FAR *LPWSADATA;

 

其中

wVersion:为Winsock版本号;

wHighVersion:返回现有Winsock最高版本;

szDescription和szSystemStatus:由特定的Winsock实施方案设定,用户在使用过程中无需设定;

iMaxSockets和iMaxUdpDg:分别为 可同时打开的套接字最大数目 和 数据报最大长度,一般不要使用它们,如果想知道数据报最大长度,应该使用WSAEnumProtocols函数来查询协议信息,而可同时打开套接字的最大数目不是固定的,和可使用内存量有关;

lpVendorInfo:是为Winsock实施方案有关的指定厂商预留的,一般使用不到

 

终止

调用int WSACleanup(void)函数终止对Winsock DLL的使用,并释放资源,以备下次使用。成功返回0,否则返回错误。

 

2.错误检查

调用int WSAGetLastError(void)函数可以获得错误代码。

 

3.流套接字编程模型

(1)服务器进程先于客户进程启动

 

    i)调用SOCKET socket(int af, int type, int protocol)函数创建一个套接字,其中

af:用于指定网络地址类型,一般取AF_INET,标识该套接字在Internet域中进行通信;

type:用于指定套接字类型,若取SOCK_STREAM标识要创建的套接字是流套接字,取SOCK_DGRAM则创建数据报套接字;

protocol:用于指定网络协议,一般取0,表示TCP/IP协议

若套接字创建成功,则返回所创建套接字句柄SOCKET,否则产生INVALID_SOCKET错误。

 

    ii)调用int bind(SOCKET s, const struct sockaddr *name, int namelen)将本地地址绑定到所创建的套接字上,其中

s:为先前创建的套接字;

name:为赋予套接字的地址,结构如下

struct sockaddr

{

    u_short sa_family;

    char sa_data[14];

}

 

struct sockaddr_in {
        short   sin_family;
        u_short sin_port;
        struct  in_addr sin_addr;
        char    sin_zero[8];
};

 

sin_family:必须设为AF_INET,标识该socket处于Internet域;

sin_port:用于指定服务端口,如果端口号设置为0,则Winsock将为应用程序分配一个值在1024至5000之间的唯一的端口;

sin_addr:用于把一个IP保存为一个四字节的数,无符号长整型数类型。可以使用函数unsigned long PASCAL FAR inet_addr (IN const char FAR * cp)将IP地址字符串转换为四字节无符号长整型数。该值取为INADDR_ANY将允许监听每个网络接口上的客户机活动;

sin_zero:无实际用处;

bind()函数的作用是将一个套接字和指定的网络地址关联在一起,让套接字等候进入链接的API函数则是listen()函数

    iii)调用int listen(SOCKET s, int backlog)键套接字置入监听模式,并准备接受请求,其中

s:为先前创建的套接字;

backlog:指定在等待链接的最大列队长度;

 

    iv)调用SOCKET accept(SOCKET s, struct sockaddr *addr, int *addrlen)接受客户端请求,并向客户端返回接收信号

s:为处于监听模式的套接字;

addr:SOCKADDR_IN结构,将包含发出链接请求的客户机IP地址信息;

addrlen:为addr的长度;

返回值:一个新的套接字,它对应于已接受的那个客户机链接,对该客户机的后续操作都应该使用该套接字。

 

(2)客户端

 

    i)调用socket()函数创建客户端套接字;

 

    ii)调用int connect(SOCKET s, const struct sockaddr FAR *name, int namelen)函数想服务器端发送链接请求,其中

s:一个未链接的Socket;

name:针对TCP的套接字地址结构,它标识服务器进程IP地址信息;

namelen:name参数的长度。

常见错误:

WSAEADDRNOTAVAIL->name成员全为零错误;

WSAECONNREFUSED->服务器端没有进程监听指定端口;

WSAETIMEDOUT->链接超时;

 

(3)数据发送和接收

 

    i)调用int send(SOCKET s, const char * buf, int len, int flags)函数发送数据,其中

s:为已建立链接的套接字;

buf:为要发送的数据内容;

len:要发送数据长度;

flags:[0]、[MSG_DONTROUTE]要求传输层不要将其发出的包路由出去、[MSG_OOB]标志数据应为带外发送,可以是三者按位或;

返回值:发送字节数

常见错误:

WSAECONNABORTED->虚拟回路由于超时或协议中有错误而中断,发生该错误时,应该关闭该套接字;

WSAECONNRESET->远程机上的套接字被强行或意外关闭;

WSAETIMEOUT->网络故障或远程机意外死机而引起的链接中断;

 

    ii)调用int recv(SOCKET s, char *buf, int len, int flags)

s:准备接受数据的套接字;

buf:即将收到数据的字符缓冲区;

len:buf缓冲区长度;

flagship:[0]无特殊行为、[MSG_PEEK]是有用的数据复制到所提供的接收端缓冲、[MSG_OOB],或者他们的按位或

返回值:接收字节数

 

(4)关闭套接字

    i)调用int shutdown(SOCKET s, int how)函数中断链接,其中

s:处于链接状态的Socket;

how:用于描述禁止那些操作,[SD_RECEIVE][SD_SEND][SD_BOTH];

返回值:成功为0,否则返回错误

 

    ii)调用int closesocket(SOCKET s)函数关闭套接字

 

流程图

 

 4.数据报套接字编程模型

数据报套接字是无链接的,编程模式相对简单。

    i)对于接收端,先用socket()函数建立套接字,在通过bind()函数把套接字和准备接受数据的IP地址绑定,这和前面的流套接字是一致的,但不同的是它不必调用listen()和accept()函数,只需等待接收数据。并且是无链接的,因此可以接受网络上的任何一台计算机所发的数据报,常用的接收函数是int recvfrom(SOCKET s, char * buf, int len, int flags, struct sockaddr * from, int * fromlen)前面四个参数和recv()一样,当收到数据时,from中将被填入发送端IP地址

 

    ii)对于发送端,先建立套接字,然后调用int sendto(SOCKET s, const char * buf, int len, int flags, const struct sockaddr *to, int tolen)函数,其中to中包含接受数据端IP地址。

 

    iii)因为数据报套接字没有链接,所有只需直接调用closesocket()函数关闭套接字即可。

 

流程图

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值