Winsock编程基础介绍 .
相信很多人都对网络编程感兴趣,下面我们就来介绍,在网络编程中应用最广泛的编程接口Winsock API.
使用Winsock API的编程,应该了解一些TCP/IP的基础知识.虽然你可以直接使用Winsock API来写网络应用程序,但是,要写出优秀的网络应用程序,还是必须对TCP/IP协议有一些了解的.
1. TCP/IP协议与Winsock网络编程接口的关系.
在开始之前,我们先说一下Winsock和TCP/IP到底是什么关系.
我碰到很多人问我:怎样使用Winsock协议编程?其实,这话说的有点错误,Winsock并不是一种网络协议,他只是一个网络编程接口,也就是说,他不是协议,但是他可以访问很多种网络协议,你可以把他当作一些协议的封装.现在的Winsock已经基本上实现了与协议无关.你可以使用Winsock来调用多种协议的功能.
那么,Winsock和TCP/IP协议到底是什么关系呢?实际上,Winsock就是tcp/ip协议的一种封装,你可以通过调用winsock的接口函数来调用tcp/ip的各种功能.例如我想用Tcp/ip协议发送数据,你就可以使用winsock的接口函数send()来调用tcp/ip的发送数据功能,至于具体怎么发送数据,Winsock已经帮你封装好了这种功能.
2.TCP/IP协议介绍
现在来介绍一些tcp/ip的原理.tcp/ip协议包含的范围非常的广,他是一种四层协议,包含了各种,硬件软件需求的定义,我们这里只介绍软件方面的知识.tcp/ip协议确切的说法应该是tcp/udp/ip协议.
udp协议(User Datagram Protocol用户数据报协议).是一种保护消息边界的,不保障可靠数据的传输. tcp协议(Transmission Control Protocol 传输控制协议).是一种流传输的协议.他提供可靠的,有序的,双向的,面向连接的传输.
3.保护消息边界和流
那么什么是保护消息边界和流呢?
保护消息边界,就是指传输协议把数据当作一条独立的消息在网上传输,接收端只能接收独立的消息.也就是说存在保护消息边界,接收端一次只能接收发送端发出的一个数据包.而面向流则是指无保护消息保护边界的,如果发送端连续发送数据,接收端有可能在一次接收动作中,会接收两个或者更多的数据包.
我们举个例子来说,例如,我们连续发送三个数据包,大小分别是2k, 4k , 8k,这三个数据包,都已经到达了接收端的网络堆栈中,如果使用UDP协议,不管我们使用多大的接收缓冲区去接收数据,我们必须有三次接收动作,才能够把所有的数据包接收完.而使用TCP协议,我们只要把接收的缓冲区大小设置在14k以上,我们就能够一次把所有的数据包接收下来.只需要有一次接收动作.
这就是因为UDP协议的保护消息边界使得每一个消息都是独立的.而流传输,却把数据当作一串数据流,他不认为数据是一个一个的消息.
所以有很多人在使用tcp协议通讯的时候,并不清楚tcp是基于流的传输,当连续发送数据的时候,他们时常会认识tcp会丢包.其实不然,因为当他们使用的缓冲区足够大时,他们有可能会一次接收到两个甚至更多的数据包,而很多人往往会忽视这一点,只解析检查了第一个数据包,而已经接收的其他数据包却被忽略了.所以大家如果要作这类的网络编程的时候,必须要注意这一点.
。Winsock编程简单流程
下面我们介绍一下Win32平台的Winsock编程方法.通讯则必须有服务器端,和客户端.我们简单介绍tcp服务器端的大体流程.
对于任何基于Winsock的编程首先我们必须要初始化Winsock DLL库.
int WSAStarup( WORD wVersionRequested , LPWSADATA lpWsAData ).
wVersionRequested是我们要求使用的Winsock的版本.
调用这个接口函数可以帮我们初始化Winsock .然后我们必须创建一个套接字(socket). SOCKET socket( int af , int type , int protocol );
套接字可以说是Winsock通讯的核心.Winsock通讯的所有数据传输,都是通过套接字来完成的,套接字包含了两个信息,一个是IP地址,一个是Port端口号,使用这两个信息,我们就可以确定网络中的任何一个通讯节点.
当我们调用了socket()接口函数创建了一个套接字后,我们必须把套接字与你需要进行通讯的地址建立联系,我们可以通过绑定函数来实现这种联系.
int bind(SOCKET s , const struct sockaddr FAR* name , int namelen ) ;
struct sockaddr_in{
short sin_family ;
u_short sin_prot ;
struct in_addr sin_addr ;
char sin_sero[8] ;
}
就包含了我们需要建立连接的本地的地址,包括,地址族,ip和端口信
息.sin_family字段我们必须把他设为AF_INET,这是告诉Winsock使
用的是IP地址族.sin_prot 就是我们要用来通讯的端口号.sin_addr
就是我们要用来通讯的ip地址信息.
在这里,必须还得提一下有关'大头(big-endian)'小头(little-endian)'.
因为各种不同的计算机处理数据时的方法是不一样的,Intel 86处理
器上是用'小头'形势来表示多字节的编号,就是把低字节放在前面,
把高字节放在后面,而互联网标准却正好相反,所以,我们必须把主机
字节转换成网络字节的顺序.Winsock API提供了几个函数.
把主机字节转化成网络字节的函数;
u_long htonl( u_long hostlong );
u_short htons( u_short hostshort );
把网络字节转化成主机字节的函数;
u_long ntohl( u_long netlong ) ;
u_short ntohs( u_short netshort ) ;
这样,我们设置ip地址,和port端口时,就必须把主机字节转化成网络
字节后,才能用bind()函数来绑定套接字和地址.
当绑定完成之后,服务器端必须建立一个监听的队列来接收客户端的
连接请求.
int listen( SOCKET s ,int backlog );
这个函数可以让我们把套接字转成监听模式.
如果客户端有了连接请求,我们还必须使用
int accept( SOCKET s , struct sockaddr FAR* addr , int FAR* addrlen );
来接受客户端的请求.
现在我们基本上已经完成了一个服务器的建立,
而客户端的建立的流程则是初始化WinSock ,然后创建socket套接字
,再使用
int connect( SOCKET s , const struct sockaddr FAR* name , int namelen ) ;
来连接服务端.
下面是一个最简单的创建服务器端和客户端的例子:
服务器端的创建 :
WSADATA wsd ;
SOCKET sListen ;
SOCKET sclient ;
UINT port = 800 ;
int iAddrSize ;
struct sockaddr_in local , client ;
WSAStartup( 0x11 , &wsd );
sListen = socket ( AF_INET , SOCK_STREAM , IPPOTO_IP ) ;
local.sin_family = AF_INET ;
local.sin_addr = htonl( INADDR_ANY ) ;
local.sin_port = htons( port ) ;
bind( sListen , (struct sockaddr*)&local , sizeof( local ) ) ;
listen( sListen , 5 ) ;
sClient = accept( sListen , (struct sockaddr*)&client , &iAddrSize ) ;
客户端的创建:
WSADATA wsd ;
SOCKET sClient ;
UINT port = 800 ;
char szIp[] = "127.0.0.1" ;
int iAddrSize ;
struct sockaddr_in server ;
WSAStartup( 0x11 , &wsd );
sClient = socket ( AF_INET , SOCK_STREAM , IPPOTO_IP ) ;
server.sin_family = AF_INET ;
server.sin_addr = inet_addr( szIp ) ;
server.sin_port = htons( port );
connect( sClient , (struct sockaddr*)&server , sizeof( server ) ) ;
当服务器端和客户端建立连接以后,无论是客户端,还是服务器端都
可以使用
int send( SOCKET s , const char FAR* buf , int len , int flags );
int recv( SOCKET s , char FAR* buf , int len , int flags );
函数来接收和发送数据,因为,TCP连接是双向的.
当要关闭通讯连结的时候,任何一方都可以调用
int shutdown( SOCKET s , int how ) ;
来关闭套接字的指定功能。再调用
int closesocket( SOCKET s) ;
来关闭套接字句柄。这样一个通讯过程就算完成了。
注意:上面的代码没有任何检查函数返回值,如果你作网络编程就一定要
检查任何一个Winsock API函数的调用结果,因为很多时候函数调用
并不一定成功.上面介绍的函数,返回值类型是int的话,如果函数调
用失败的话,返回的都是SOCKET_ERROR.
。Winsock编程的五种模型
上面介绍的仅仅是最简单的winsock通讯的方法,而实际中很多网络
通讯的却很多难以解决的意外情况.
例如,Winsock提供了两种套接字模式:锁定和非锁定.当我们使用锁
定套接字的时候,我们使用的很多函数,例如accpet,send,recv等等,
如果没有数据需要处理,这些函数都不会返回,也就是说,你的应用程
序会阻塞在那些函数的调用处.而 如果使用非阻塞模式,调用这些函
数,不管你有没有数据到达,他都会返回,所以,有可能我们在非阻塞
模式里,调用这些函数大部分的情况下会返回失败,所以就需要我们
来处理很多的意外出错.
这显然不是我们想要看到的情况.我们可以采用Winsock的通讯模型
来避免这些情况的发生。
Winsock提供了五种套接字I/O模型来解决这些问题.他们分别是
select(选择),WSAAsyncSelect(异步选择),
WSAEventSelect (事件选择), overlapped(重叠) , completion
port(完成端口) .
我们在这里详细介绍一下select,WSAASyncSelect两种模型.
select模型是最常见的I/O模型.
使用
int select( int nfds , fd_set FAR* readfds , fd_set FAR* writefds , fd_set FAR* exceptfds ,
const struct timeval FAR * timeout ) ;
函数来检查你要调用的socket套接字是否已经有了需要处理的数据.
select包含三个socket队列,分别代表:
readfds ,检查可读性,writefds,检查可写性,exceptfds,例外数据.
timeout是select函数的返回时间.
例如,我们想要检查一个套接字是否有数据需要接收,我们可以把套
接字句柄加入可读性检查队列中,然后调用select,如果,该套接字没
有数据需要接收,select函数会把该套接字从可读性检查队列中删除
掉,所以我们只要检查该套接字句柄是否还存在于可读性队列中,就
可以知道到底有没有数据需要接收了.
Winsock提供了一些宏用来操作套接字队列fd_set.
FD_CLR( s,*set) 从队列set删除句柄s.
FD_ISSET( s, *set) 检查句柄s是否存在与队列set中.
FD_SET( s,*set )把句柄s添加到队列set中.
FD_ZERO( *set ) 把set队列初始化成空队列.
WSAAsyncSelect(异步选择)模型:
WSAASyncSelect模型就是把一个窗口和套接字句柄建立起连接,套接
字的网络事件发生时时候,就会把某个消息发送到窗口,然后可以在
窗口的消息响应函数中处理数据的接收和发送.
int WSAAsyncSelect( SOCKET s, HWND hWnd , unsigned int wMsg , long lEvent ) ;
这个函数可以把套接字句柄和窗口建立起连接,
wMsg 是我们必须自定义的一个消息.
lEvent就是制定的网络事件.包括FD_READ , FD_WRITE , FD_ACCEPT
, FD_CONNECT , FD_CLOSE .
几个事件.
例如,我需要接收FD_READ , FD_WRITE , FD_CLOSE的网络事件.可
以调用
WSAAsyncSelect( s , hWnd , WM_SOCKET , FD_READ | FD_WRITE | FD_CLOSE ) ;
这样,当有FD_READ , FD_WRITE或者 FD_CLOSE网络事件时,窗口
hWnd将会收到WM_SOCKET消息,消息参数的lParam标志了是什么事件
发生.
其实大家应该见过这个模型,因为MFC的CSocket类,就是使用这个模
型.
Winsock编程基础介绍 .的更多相关文章
- shell脚本编程基础介绍
Linux系统——shell脚本编程基础介绍 1.什么是shell 它是一个命令解释器,在linux/unix操作系统的最外层,负责直接与用户对话,把用户的输入解释给操作系统,并处理各种操作输出的结果 ...
- <转>Socket编程——基础介绍
最近系统的看了下unix网络编程的一些内容,对socket的理解有了进一步的加深,在看APUE的时候,那会儿看socket上面介绍的比较少,只是模糊的懂了如何去写一个简单的TCP服务端和客户端,对其中 ...
- Winsock编程基础2(Winsock编程流程)
1.套接字的创建和关闭 //创建套接字 SOCKET socket( int af, //指定套接字使用的地址格式,Winsock只支持AF_INET int type, //套接字类型 int pr ...
- Winsock编程基础1
1.加载和释放Winsoke库 //所有Winsock函数都是从WS2_32.DLL导出,包含相应库文件#include <winsock2.h>#pragma comment(lib, ...
- shell脚本之编程基础介绍
1.shell脚本简介 1.1 shell是什么? shell是一个命令解释器,它在操作系统的最外层负责直接与用户对话,把用户的输入解释给操作系统:并处理各种各样的操作系统的输入,将结果输出到屏幕返回 ...
- WinSock编程基础
一.套接字模式 1.阻塞模式 创建套接字时,默认是阻塞模式,对recv函数调用会使程序进入等待状态,知道接收到数据才返回. 2.非阻塞模式: 可以调用ioctlsocke ...
- Winsock编程基础2(UDP流程)
UDP用户数据报协议 服务器端 <1 创建套接字(socket) <2 绑定IP地址和端口(bind) <3 收发数据(sendto, recvfrom) <4 关闭连接(cl ...
- Web3D编程入门总结——WebGL与Three.js基础介绍
/*在这里对这段时间学习的3D编程知识做个总结,以备再次出发.计划分成“webgl与three.js基础介绍”.“面向对象的基础3D场景框架编写”.“模型导入与简单3D游戏编写”三个部分,其他零散知识 ...
- Hadoop 综合揭秘——MapReduce 基础编程(介绍 Combine、Partitioner、WritableComparable、WritableComparator 使用方式)
前言 本文主要介绍 MapReduce 的原理及开发,讲解如何利用 Combine.Partitioner.WritableComparator等组件对数据进行排序筛选聚合分组的功能.由于文章是针对开 ...
随机推荐
- objective-C学习笔记(九)ARC
ARC叫自动引用计数Automatic Reference Counting.针对堆上的对象,管理对象的创建和释放. 哪些对象受ARC管理: OC对象指针 Block指针 使用_attribute_( ...
- C#线程(一)
本篇作为自己简要的笔记和整理,自己英语略渣 就不翻译了 参考http://www.albahari.com/threading 这里有翻译的http://www.cnblogs.com/miniwi ...
- 线段树讲解(数据结构、C++)
声明 : 仅一张图片转载于http://www.cnblogs.com/shuaiwhu/archive/2012/04/22/2464583.html,自己画太麻烦了...那个博客的讲解也很好 ...
- mysql server5.6.28 修改数据目录
1.查看配置文件 mysql --help | grep my.cnf 列出使用哪个配置文件(顺序推) 2.service mysql stop 3.创建新目录 mkdir /data 4.迁移之前的 ...
- Linq 入门 顺带 Func与Action
Linq的优点: 查询是一种从数据源检索数据的表达式. 查询通常用专门的查询语言来表示. 随着时间的推移,人们已经为各种数据源开发了不同的语言:例如,用于关系数据库的 SQL 和用于 XML 的 XQ ...
- thinkphp phpexcel导出
近期做一个项目涉及到商品信息的批量导出与导入,遂记录了下来,框架是tp框架3.2.3(tp5.0性质是一样的,无非是加载方法与所放目录不一样罢了),运用的是phpexcel,闲话不多说,上代码 1.首 ...
- 在iOS上增加手势锁屏、解锁功能
在iOS上增加手势锁屏.解锁功能 在一些涉及个人隐私的场景下,尤其是当移动设备包含太多私密信息时,为用户的安全考虑是有必要的. 桌面版的QQ在很多年前就考虑到用户离开电脑后隐私泄露的危险,提供了“离开 ...
- 交换右ctrl和capslock
记得几年前开始使用Emacs,因为使用ctrl键太频繁了,所以上网查了下解决方案,看到这篇文章 .把capslock和左ctrl交换,简直要泪流满面啊!立马照着做,从此在所有使用的电脑上都对此进行了设 ...
- 【图文教程】用“iz3d”软件将您的游戏打造为红蓝3D游戏。
iz3d是一款能将普通3D游戏转换为红蓝3D游戏的软件.基本上支持所有游戏,或许没用过的人会认为这只是类似于播放器中的一个小功能,将平面图形做成“伪3D”红蓝效果. 实际上不是的,游戏与平面图的结构不 ...
- DropDownList控件学习
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...