近期看了《Window程序设计》感觉在网络方面讲的不错,讲的非常通俗易懂。与大家一同交流

转载请注明出处:http://blog.csdn.net/u010484477谢谢^_^

使用 Winsock 编程的一般步骤是比較固定的。



1.Winsock 库的装入、初始化和释放



全部的 WinSock 函数都是从 WS2_32.DLL 库导出的。VC++在默认情况下并没有连接到该库,假设想使用 Winsock API。就必须包括对应的库文件。

#pragma commment(lib, "wsock32.lib")

WSAstartup 必须是应用程序首先调用的 Winsock 函数。它同意应用程序指定所需的Windows Sockets API 的版本号,获取特定 Winsock 实现的具体信息。仅当这个函数成功运行之后。应用程序才干调用其它 Winsock API。

int WSAStartup(

WORD wVersionRequested, // 应用程序支持的最高WinSock库版本号。高字节为次版本号号,低字节为主版本号号

LPWSADATA lpWSAData // 一个指向WSADATA结构的指针。它用来返回DLL 库的具体信息

);

lpWSAData 參数用来取得 DLL 库的具体信息。结构定义例如以下。

typedef struct WSAData {

WORD wVersion;
// 库文件建议应用程序使用的版本号

WORD wHighVersion;// 库文件支持的最高版本号

char szDescription[WSADESCRIPTION_LEN+1]; // 库描写叙述字符串

char szSystemStatus[WSASYS_STATUS_LEN+1]; // 系统状态字符串

unsigned short iMaxSockets;// 同一时候支持的最大套节字的数量

unsigned short iMaxUdpDg;// 2.0 版中已废弃的參数

char FAR * lpVendorInfo;
// 2.0 版中已废弃的參数

} WSADATA, FAR * LPWSADATA;

函数调用成功返回 0。否则要调用 WSAGetLastError 函数查看出错的原因。此函数的作用相当于 Win32 API GetLastError。它取得最后错误发生的代码。

每个对WSAStartup的调用必须相应一个对WSACleanup的调用。这个函数释放Winsock库。

int  WSACleanup(void);

2.套节字的创建和关闭



使用套节字之前,必须调用 socket 函数创建一个套节字对象,此函数调用成功将返回套节字句柄

SOCKET socket(

int af,// 用来指定套节示使用的地址格式。WinSock中仅仅支持AF_INET

int type,// 用来指定套节字的类型

int protocol// 配合type 參数使用,用来指定使用的协议类型。能够是IPPROTO_TCP等

);

type 參数用来指定套节字的类型。

套节字有流套节字、数据报套节字和原始套节字等,

以下是常见的几种套节字类型定义:

SOCK_STREAM 流套节字。使用 TCP 协议提供有连接的可靠的传输

SOCK_DGRAM 数据报套节字,使用 UDP 协议提供无连接的不可靠的传输

SOCK_RAW 原始套节字,WinSock 接口并不使用某种特定的协议去封装它。而是有程序自行处理数据报以及协议首部

当 type 參数指定为 SOCK_STREAM 和 SOCK_DGRAM 时。系统已经明白确定使用 TCP和 UDP 协议来工作,所以 protocol 參数能够指定为 0。

函数运行失败返回 INVALID_SOCKET(即-1),能够通过调用 WSAGetLastError 取得错误代码。

当不使用 socket 创建的套节字时,应该调用 closesocket 函数将它关闭。假设没有发生错误,函数返回 0。否则返回 SOCKET_ERROR。

closesocket函数使用方法例如以下。

int closesocket(SOCKET s); // 函数惟一的參数就是要关闭的套节字的句柄

3.绑定套节字到指定的 IP 地址和port号



为套节字关联本地地址的函数是 bind,使用方法例如以下。

int bind(

SOCKET s,// 套节字句柄

const struct sockaddr* name,// 要关联的本地地址

int namelen// 地址的长度

     );

bind 函数用在没有建立连接的套节字上,它的作用是绑定面向连接的或者无连接的套节字。当一个套节字被 socket 函数创建以后,他存在于指定的地址家族里,可是它是未命名的。

bind 函数通过安排一个本地名称到未命名的 socket 建立此 socket 的本地关联。

本地名称包括 3个部分:主机地址、协议号(分别为 UDP 或 TCP)和port号。

// 填充sockaddr_in结构

sockaddr_in sin;

sin.sin_family = AF_INET;

sin.sin_port = htons(8888);

sin.sin_addr.S_un.S_addr = INADDR_ANY;

// 绑定这个套节字到一个本地地址

if(::bind(s, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)

{

printf("Failed bind() \n");

::WSACleanup();

return 0;

}

sockaddr_in 结构中的 sin_familly 字段用来指定地址家族。该字段和 socket 函数中的 af 參数的含义同样。所以惟一能够使用的值就是 AF_INET。

sin_port 字段和 sin_addr 字段分别指定套节字须要绑定的端口号
IP 地址

放入这两个字段的数据的字节顺序必须是网络字节顺序

因为网络字节顺序和 Intel CPU 的字节顺序刚好相反,所以必须首先用 htons 函数进行转换。假设应用程序不关心所使用的地址。能够为互联网地址指定 INADDR_ANY,为port号指定 0。假设互联网地址等于 INADDR_ANY,系统会自己主动使用当前主机配置的全部 IP 地址,这简化了程序设计;假设port号等于 0,程序运行时系统会分配一个惟一的port号到这个应用程序,其值在 1024 到 5000 之间。应用程序能够在 bind 之后使用 getsockname 来知道为它分配的地址。可是要注意。直到套节字连接上之后
getsockname 才可能填写互联网地址,由于对一个主机来说可能有多个地址是可用的。

4.设置套节字进入监听状态



listen 函数置套节字进入监听状态。

int listen(

SOCKET s,// 套节字句柄

int backlog// 监听队列中同意保持的尚未处理的最大连接数量

);

为了接受连接,首先使用 socket 函数创建一个套节字,然后使用
bind 函数绑定它到一个本地地址,再用
listen 函数为到达的连接指定一个 backlog。最后使用 accept 接受请求的连接。

listen 仅应用在支持连接的套节字上,如 SOCK_STREAM 类型。函数成功运行之后,套节字 s 进入了被动模式,到来的连接会被通知,排队等候接受处理。

在同一时间处理多个连接请求的server通常使用 listen 函数:假设一个连接请求到达,而且排队已满,client将接接收 WSAECONNREFUSED 错误。

5.接受连接请求

accept 函数用于接受到来的连接。

SOCKET accept(

SOCKET s,// 套节字句柄

struct sockaddr* addr,// 一个指向sockaddr_in结构的指针。用于取得对方的地址信息

int* addrlen// 是一个指向地址长度的指针

    );

该函数在 s 上取出未处理连接中的第一个连接,然后为这个连接创建一个新的套节字,返回它的句柄。新创建的套节字是处理实际连接的套节字,它与 s 有同样的属性。

程序默认工作在堵塞模式下,这样的方式下假设没有未处理的连接存在,accept 函数会一直等待下去直到有新的连接发生才返回。

addrlen 參数用于指定 addr 所指空间的大小。也用于返回返回地址实际长度

假设 addr或者 addrlen 是 NULL,则没有关于远程地址的信息返回。client程序在创建套节字之后,要使用 connect 函数请求与server连接。函数原型例如以下。

int connect(

SOCKET s,// 套节字句柄

const struct sockaddr FAR * name, // 一个指向 sockaddr_in 结构的指针。包括了要连接的server的地址信息。

int namelen// sockaddr_in结构的长度

   );

第一个參数 s 是此连接使用的client套节字。另两个參数 name 和 namelen 用来寻址远程套节字(正在监听的server套节字)。

6.收发数据



对流套节字来说,一般使用 send 和 recv 函数来收发数据。



int send(

SOCKET s,// 套节字句柄

const char FAR * buf,// 要发送数据的缓冲区地址

int len,// 缓冲区长度

int flags// 指定了调用方式,通常设位0

     );

int recv( SOCKET s, char FAR * buf, int len, int );

send 函数在一个连接的套节字上发送缓冲区内的数据,返回发送数据的实际字节数。

recv函数从对方接收数据,并存储指定的缓冲区。flags 參数在这两函数中通常设为 0。

在堵塞模式下。send 将会堵塞线程的运行直到全部的数据发送完成(或者一个发生错误),

    recv 函数将返回尽可能多的当前可用信息。一直到缓冲区指定的大小。

下图为server程序和客户程序的创建过程:


最后是送大家一句我非常喜欢的话:

你必须用自己的努力换取成功,然后成功就会像一个大巴掌,打在那些以前看不起你的人脸上

Winsock 编程流程的更多相关文章

  1. Winsock编程基础2(Winsock编程流程)

    1.套接字的创建和关闭 //创建套接字 SOCKET socket( int af, //指定套接字使用的地址格式,Winsock只支持AF_INET int type, //套接字类型 int pr ...

  2. Winsock编程基础介绍 .

    相信很多人都对网络编程感兴趣,下面我们就来介绍,在网络编程中应用最广泛的编程接口Winsock API. 使用Winsock API的编程,应该了解一些TCP/IP的基础知识.虽然你可以直接使用Win ...

  3. winsock编程WSAAsyncSelect模型

    winsock编程WSAAsyncSelect模型 WSAAsyncSelect模型也称异步选择模型,其核心函数是WSAAsyncSelect.它可以用来在一个socket上接收以windows消息为 ...

  4. NetBIOS与Winsock编程接口

    最近在看网络编程方面的书,由于不是通信专业出身的,以前理解的网络体系感觉就是tcp/ip,最近工作上接触到了一些光环网等乱七八糟的东西,有些基本的LC.SC连接器都不认识.花时间看了下计算机网络体系结 ...

  5. 2.1 LibCurl编程流程(转)

    转载地址:http://blog.chinaunix.net/u/17660/showart_1822514.html2 LibCurl编程2.1 LibCurl编程流程在基于LibCurl的程序里, ...

  6. winsock编程IOCP模型实现代码

    winsock编程IOCP模型实现代码 话不多说,上代码.借鉴<windows核心编程>部分源码和CSDN小猪部分代码. stdafx.h依赖头文件: #include <iostr ...

  7. winsock编程WSAEventSelect模型

    winsock编程WSAEventSelect模型 WSAEventSelect模型和WSAAsyncSelec模型类似,都是用调用WSAXXXXXSelec函数将socket和事件关联并注册到系统, ...

  8. winsock编程select模型

    winsock编程select模型 网络服务端连接数量过多时,为每一个连接申请一个线程会让机器性能急剧下降(大多说是因为线程在用户态和内核态之间切换会占用大量的CPU时间片).为了解决多线程带来的性能 ...

  9. Delphi下的WinSock编程

    一.定址        要通过Winsock建立通信,必须了解如何利用指定的协议为工作站定址.Winsock 2引入了几个新的.与协议无关的函数,它们可和任何一个地址家族一起使用:但是大多数情况下,各 ...

随机推荐

  1. 改变Emacs下的注释代码方式以支持当前行(未选中情况下)的注释/反注释

    Emacs下支持多行代码的注释/反注释,命令是comment-or-uncomment-region. 我喜欢把它绑定在快捷键C-c C-/上,如下: (global-set-key [?\C-c ? ...

  2. readline-6.3 之arm平台交叉编译

    近期须要弄个CLI命令接口程序,初步设想是须要支持历史命令翻阅,tab键命令补全这种一个东西.经查阅相关文档,深耕百度一番!(google近期不太正常) 实在恼火.发现readline果真是个好东西, ...

  3. 挑战一下吧!C#测试开发工程师英语面试题

    1. Given a rectangular (cuboidal for the puritans) cake with a rectangular piece removed (any size o ...

  4. [置顶] Jsp中的table多表头导出excel文件

    首先引入两份JS:copyhtmltoexcel.js以及 tableToExcel.js /* * 默认转换实现函数,如果需要其他功能,需自行扩展 * 参数: * tableID : HTML中Ta ...

  5. .Net 4.0特性 Tuple元组

    Tuple 字面意思:元组.是.net4.0增加的新特性,是干什么的呢?总结一句,个人觉得这个东西 就是用来在有返回很多种类型的值时可以用到.它提供了8种类型的Tuple,直接看最复杂的那种(其实不是 ...

  6. char *和char[]的区别,困扰很长时间了,总结下

    char c1[] = "hello";// char *c2 = "hello";// 区别1: c1是一个局部数组,c2是一个全局数组. 局部数组c1是局部 ...

  7. mysql 父子结构排序

    项目中常常会遇到父子结构显示的问题,不同的数据库有不同的写的方式,比方SqlServer中用with union 实现.而Mysql则没有这么方便的语句. 例如以下category表.食品有pizaa ...

  8. freemarker的TemplateExceptionHandler使用

    系统使用freemarker作为页面展示层,为了解决系统统一异常的问题.于是配置了struts2的统一异常解决的方法(这个网上资料非常多,大家能够查看),但是发现freemarker出现异常后,str ...

  9. win32 字体变换与窗口同大同小

    #include <windows.h> #include "res/resource.h" LRESULT CALLBACK WinProc(HWND hwnd, U ...

  10. hdu1392 Surround the Trees 凸包

    第一次做凸包,这道题要特殊考虑下,n=2时的情况,要除以二才行. 我是从最左边的点出发,每次取斜率最大的点,一直到最右边的点. 然后从最左边的点出发,每次取斜率最低的点,一直到最右边的点. #incl ...