论坛登陆 用户: 密码:
联系我们
设为首页
加入收藏
业界新闻 网络编程 程序开发 网页图象 聊天通讯 软件应用 网络安全 硬件学堂 教育频道 站长club
  ·推荐新闻
 
·美前任官员认为amd告倒英特
·搜索引擎关键字排行简介
·网站优化教程(一)
·msn近期遭受木马病毒骚扰 用
·用qq管理你的系统^_^ 
·测评中心金山毒霸联合发布7
·qq群聊实名 普通用户不受影
·雅虎思科联手推数字邮件签名
·这18条背下来没人敢和你忽悠
·自己动手,拯救丢失的硬盘数
  ·资料搜索
 
  ·相关文章
·mysql和sqlserver,到底选择谁
·循序渐进学习power builder 6.
·循序渐进学习power builder 6.
·循序渐进学习power builder 6.
·循序渐进学习power builder 6.
·循序渐进学习power builder 6.
·循序渐进学习power builder 6.
·循序渐进学习power builder 6.
·循序渐进学习power builder 6.
·循序渐进学习power builder 6.
  ·热门新闻

winsock学习笔记(一)


 日期:2005-7-18 9:18:58     来源:易特网络技术   编辑:黑鹰  点击:
来源:http://www.vckbase.com/document/viewdoc/?id=1035

winsock学习笔记(一)


作者:肖进



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。其实就是计算机的ip地址,不过一般不用用点分开的ip地
址,当然也提供一些转换函数。

◆ 旧的网络地址结构的定义,为一个4字节的联合:

struct in_addr {
union {
struct { u_char s_b1,s_b2,s_b3,s_b4; } s_un_b;
struct { u_short s_w1,s_w2; } s_un_w;
u_long s_addr;
} s_un;
#define s_addr s_un.s_addr /* can be used for most tcp & ip code */
//下面几行省略,反正没什么用处。
};

其实完全不用这么麻烦,请看下面:

◆ 新的网络地址结构的定义:
非常简单,就是一个无符号长整数 unsigned long。举个例子:ip地址为127.0.0.1的网络地址是什么呢?请看定义:

#define inaddr_loopback 0x7f000001

3、 套接字地址结构

(1)、sockaddr结构:

struct sockaddr {
u_short sa_family; /* address family */
char sa_data[14]; /* up to 14 bytes of direct address */
};

sa_family为网络地址类型,一般为af_inet,表示该socket在internet域中进行通信,该地址结构随选择的协议的不同而变化,因此一般情况下另一个与该地址结构大小相同的sockaddr_in结构更为常用,sockaddr_in结构用来标识tcp/ip协议下的地址。换句话说,这个结构是通用socket地址结构,而下面的sockaddr_in是专门针对internet域的socket地址结构。

(2)、sockaddr_in结构

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

sin _family为网络地址类型,必须设定为af_inet。sin_port为服务端口,注意不要使用已固定的服务端口,如http的端口80等。如果端口设置为0,则系统会自动分配一个唯一端口。sin_addr为一个unsigned long的ip地址。sin_zero为填充字段,纯粹用来保证结构的大小。

◆ 将常用的用点分开的ip地址转换为unsigned long类型的ip地址的函数:

unsigned long inet_addr(const char far * cp )

用法:

unsigned long addr=inet_addr("192.1.8.84")

◆ 如果将sin_addr设置为inaddr_any,则表示所有的ip地址,也即所有的计算机。

#define inaddr_any (u_long)0x00000000

4、 主机地址:

先看定义:

struct hostent {
char far * h_name; /* official name of host */
char far * far * h_aliases; /* alias list */
short h_addrtype; /* host address type */
short h_length; /* length of address */
char far * far * h_addr_list; /* list of addresses */
#define h_addr h_addr_list[0] /* address, for backward compat */
};
h_name为主机名字。
h_aliases为主机别名列表。
h_addrtype为地址类型。
h_length为地址类型。
h_addr_list为ip地址,如果该主机有多个网卡,就包括地址的列表。

另外还有几个类似的结构,这里就不一一介绍了。

5、 常见tcp/ip协议的定义:

#define ipproto_ip 0 
#define ipproto_icmp 1 
#define ipproto_igmp 2 
#define ipproto_tcp 6 
#define ipproto_udp 17 
#define ipproto_raw 255 

具体是什么协议,大家一看就知道了。

套接字的属性

为了灵活使用套接字,我们可以对它的属性进行设定。

1、 属性内容:

//允许调试输出
#define so_debug 0x0001 /* turn on debugging info recording */
//是否监听模式
#define so_acceptconn 0x0002 /* socket has had listen() */
//套接字与其他套接字的地址绑定
#define so_reuseaddr 0x0004 /* allow local address reuse */
//保持连接
#define so_keepalive 0x0008 /* keep connections alive */
//不要路由出去
#define so_dontroute 0x0010 /* just use interface addresses */
//设置为广播
#define so_broadcast 0x0020 /* permit sending of broadcast msgs */
//使用环回不通过硬件
#define so_useloopback 0x0040 /* bypass hardware when possible */
//当前拖延值
#define so_linger 0x0080 /* linger on close if data present */
//是否加入带外数据
#define so_oobinline 0x0100 /* leave received oob data in line */
//禁用linger选项
#define so_dontlinger (int)(~so_linger)
//发送缓冲区长度
#define so_sndbuf 0x1001 /* send buffer size */
//接收缓冲区长度
#define so_rcvbuf 0x1002 /* receive buffer size */
//发送超时时间
#define so_sndtimeo 0x1005 /* send timeout */
//接收超时时间
#define so_rcvtimeo 0x1006 /* receive timeout */
//错误状态
#define so_error 0x1007 /* get error status and clear */
//套接字类型
#define so_type 0x1008 /* get socket type */

2、 读取socket属性:

int getsockopt(socket s, int level, int optname, char far * optval, int far * optlen)

s为欲读取属性的套接字。level为套接字选项的级别,大多数是特定协议和套接字专有的。如ip协议应为 ipproto_ip。

optname为读取选项的名称
optval为存放选项值的缓冲区指针。
optlen为缓冲区的长度

用法:

int ttl=0; //读取ttl值
int rc = getsockopt( s, ipproto_ip, ip_ttl, (char *)&ttl, sizeof(ttl));
//来自ms platform sdk 2003

3、 设置socket属性:

int setsockopt(socket s,int level, int optname,const char far * optval, int optlen)

s为欲设置属性的套接字。
level为套接字选项的级别,用法同上。
optname为设置选项的名称
optval为存放选项值的缓冲区指针。
optlen为缓冲区的长度

用法:

int ttl=32; //设置ttl值
int rc = setsockopt( s, ipproto_ip, ip_ttl, (char *)&ttl, sizeof(ttl));

套接字的使用步骤

1、启动winsock:对winsock dll进行初始化,协商winsock的版本支持并分配必要的
资源。(服务器端和客户端)

int wsastartup( word wversionrequested, lpwsadata lpwsadata )

wversionrequested为打算加载winsock的版本,一般如下设置:
wversionrequested=makeword(2,0)
或者直接赋值:wversionrequested=2

lpwsadata为初始化socket后加载的版本的信息,定义如下:
typedef struct wsadata {
word wversion;
word whighversion;
char szdescription[wsadescription_len+1];
char szsystemstatus[wsasys_status_len+1];
unsigned short imaxsockets;
unsigned short imaxudpdg;
char far * lpvendorinfo;
} wsadata, far * lpwsadata;

如果加载成功后数据为:

wversion=2表示加载版本为2.0。
whighversion=514表示当前系统支持socket最高版本为2.2。
szdescription="winsock 2.0"
szsystemstatus="running"表示正在运行。
imaxsockets=0表示同时打开的socket最大数,为0表示没有限制。
imaxudpdg=0表示同时打开的数据报最大数,为0表示没有限制。
lpvendorinfo没有使用,为厂商指定信息预留。

该函数使用方法:

word wversion=makeword(2,0);
wsadata wsdata;
int nresult= wsastartup(wversion,&wsdata);
if(nresult !=0)
{
//错误处理
}

2、创建套接字:(服务器端和客户端)

socket socket( int af, int type, int protocol );
af为网络地址类型,一般为af_inet,表示在internet域中使用。
type为套接字类型,前面已经介绍了。
protocol为指定网络协议,一般为ipproto_ip。

用法:

socket sock=socket(af_inet,sock_stream,ipproto_ip);
if(sock==invalid_socket)
{
//错误处理
}

3、套接字的绑定:将本地地址绑定到所创建的套接字上。(服务器端和客户端)

int bind( socket s, const struct sockaddr far * name, int namelen )
s为已经创建的套接字。
name为socket地址结构,为sockaddr结构,如前面讨论的,我们一般使用sockaddr_in
结构,在使用再强制转换为sockaddr结构。
namelen为地址结构的长度。

用法:

sockaddr_in addr;
addr. sin_family=af_inet;
addr. sin_port= htons(0); //保证字节顺序
addr. sin_addr.s_addr= inet_addr("192.1.8.84")
int nresult=bind(s,(sockaddr*)&addr,sizeof(sockaddr));
if(nresult==socket_error)
{
//错误处理
}

4、 套接字的监听:(服务器端)

int listen(socket s, int backlog )

s为一个已绑定但未联接的套接字。
backlog为指定正在等待联接的最大队列长度,这个参数非常重要,因为服务器一般可
以提供多个连接。
用法:

int nresult=listen(s,5) //最多5个连接
if(nresult==socket_error)
{
//错误处理
}

5、套接字等待连接::(服务器端)

socket accept( socket s, struct sockaddr far * addr, int far * addrlen )

s为处于监听模式的套接字。
sockaddr为接收成功后返回客户端的网络地址。
addrlen为网络地址的长度。

用法:

sockaddr_in addr;
socket s_d=accept(s,(sockaddr*)&addr,sizeof(sockaddr));
if(s==invalid_socket)
{
//错误处理
}

6、套接字的连结:将两个套接字连结起来准备通信。(客户端)

int connect(socket s, const struct sockaddr far * name, int namelen )

s为欲连结的已创建的套接字。
name为欲连结的socket地址。
namelen为socket地址的结构的长度。

用法:

sockaddr_in addr;
addr. sin_family=af_inet;
addr. sin_port=htons(0); //保证字节顺序
addr. sin_addr.s_addr= htonl(inaddr_any) //保证字节顺序
int nresult=connect(s,(sockaddr*)&addr,sizeof(sockaddr));
if(nresult==socket_error)
{
//错误处理
}

7、套接字发送数据:(服务器端和客户端)

int send(socket s, const char far * buf, int len, int flags )

s为服务器端监听的套接字。
buf为欲发送数据缓冲区的指针。
len为发送数据缓冲区的长度。
flags为数据发送标记。
返回值为发送数据的字符数。

◆这里讲一下这个发送标记,下面8中讨论的接收标记也一样:

flag取值必须为0或者如下定义的组合:0表示没有特殊行为。

#define msg_oob 0x1 /* process out-of-band data */
#define msg_peek 0x2 /* peek at incoming message */
#define msg_dontroute 0x4 /* send without using routing tables */
msg_oob表示数据应该带外发送,所谓带外数据就是tcp紧急数据。
msg_peek表示使有用的数据复制到缓冲区内,但并不从系统缓冲区内删除。
msg_dontroute表示不要将包路由出去。

用法:

char buf[]="xiaojin";
int nresult=send(s,buf,strlen(buf));
if(nresult==socket_error)
{
//错误处理
}

8、 套接字的数据接收:(客户端)

int recv( socket s, char far * buf, int len, int flags )

s为准备接收数据的套接字。
buf为准备接收数据的缓冲区。
len为准备接收数据缓冲区的大小。
flags为数据接收标记。
返回值为接收的数据的字符数。

用法:

char mess[1000];
int nresult =recv(s,mess,1000,0);
if(nresult==socket_error)
{
//错误处理
}

9、中断套接字连接:通知服务器端或客户端停止接收和发送数据。(服务器端和客户端)

int shutdown(socket s, int how)

s为欲中断连接的套接字。
how为描述禁止哪些操作,取值为:sd_receive、sd_send、sd_both。

#define sd_receive 0x00
#define sd_send 0x01
#define sd_both 0x02

用法:

int nresult= shutdown(s,sd_both);
if(nresult==socket_error)
{
//错误处理
}

10、 关闭套接字:释放所占有的资源。(服务器端和客户端)

int closesocket( socket s )

s为欲关闭的套接字。

用法:

int nresult=closesocket(s);
if(nresult==socket_error)
{
//错误处理
}
作者信息
肖进
单位:南京中萃食品有限公司 资讯部
邮箱:xiaoj@njb.swirebev.com
电话:025-58642091
上一篇:windows socket 网络编程(二)
下一篇:windows sockets 网络编程(三)
[发送给好友] [打印本页] [关闭窗口] [返回顶部转载请注明来源:http://www.iyit.net
特别声明: 本站除部分特别声明禁止转载的专稿外的其他文章可以自由转载,但请务必注明出处和原始作者。文章版权归文章原始作者所有。对于被本站转载文章的个人和网站,我们表示深深的谢意。如果本站转载的文章有版权问题请联系编辑人员,我们尽快予以更正。
责任编辑: 黑鹰 投稿作者: 易特网络
信息来源: 易特网络技术 录入时间: 2005-7-18 9:18:58
浏览次数: 投稿信箱: shtghy@163.com
设置首页 - 版权声明 - 广告服务 - 关于我们 - 联系我们 - 友情连接
copyrights ©2004-2005 iyit.net all rights reserved. 网站合作、广告联系qq:147007642、466949678
易特网络技术 点击这里给我发消息