浏览 4664 次
锁定老帖子 主题:Socket(一)
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-03-20   最后修改:2009-03-27
C++

参考:http://tech.163.com/school

        http://tb.donews.net/TrackBack.aspx?PostId=101035

VC中进行WINSOCKAPI编程开发的时候,需要在项目中使用下面三个文件,否则会出现编译错误。
  1WINSOCK.H: 这是WINSOCK API的头文件,需要包含在项目中。

  2WSOCK32.LIB: WINSOCK API连接库文件。在使用中,一定要把它作为项目的非缺省的连接库包含到项目文件中去。

  3WINSOCK.DLL: WINSOCK的动态连接库,位于WINDOWS的安装目录下。

1)在初始化阶段调用WSAStartup()

  此函数在应用程序中初始化Windows Sockets DLL ,只有此函数调用成功后,应用程序才可以再调用其他Windows Sockets DLL中的API函数。在程式中调用该函数的形式如下:

int WSAStartup (WORD wVersionRequested,LPWSADATA lpWSAData);

其中第一个参数为你所想需要的Winsock版本!低字节为主版本,高字节为副版本!由于目前Winsock有两个版本:1.12.2,因此该参数可以是0x1010x202;二个参数是一个WSADATA结构,用于接收函数的返回信息!WSAStartup函数调用成功会返回0,否则返回非0值!在DLL内部维持着一个计数器,只有第一次调用WSAStartup才真正装载DLL,以后的调用只是简单的增加计数器,而WSACleanup函数的功能则刚好相反,每调用一次使计数器减1,当计数器减到0时,DLL就从内存中被卸载!因此,你调用了多少次WSAStartup,就应相应的调用多少次的WSACleanup

使用示例:

WSADATA wsaData;
if(WSAStartup(0x101,&wsaData))
{
//
错误处理!
}

  2)建立Socket
  创建套接字有两个函数,socketWSASocket,前者是标准的Socket函数,而后者是微软对Socket的扩展函数。socket函数调用成功返回一个套接字描述符,错误则返回SOCKET_ERROR
SOCKET PASCAL FAR WSASocket ( int af, int type, int protocol )
参数:

af: 第一个是指定通信发生的区域,在UNIX下有AF_UNIXAF_INETAF_NS等,而在Winsock1.1下只支持AF_INET,到了2.2则添了AF_IRDA(红外线通信)AF_ATM(异步网络通信)AF_NSAF_IPX等。
type
2个参数是套接字的类型,在AF_INET地址族下,有SOCK_STREAMSOCK_DGRAMSOCK_RAW三种套接字类型。SOCK_STREAM也就是通常所说的TCP,而SOCK_DGRAM则是通常所说的UDP,而SOCK_RAW则是用于提供一些较低级的控制的;
protocol
依赖于第2个参数,用于指定套接字所用的特定协议,设为0表示使用默认的协议。
使用示例:

SOCKET sk;
sk=socket(AF_INET,SOCK_STREAM,0);
if(sk==SOCKET_ERROR)
{
//
错误处理
}

 

 


  3)绑定端口
  接下来要为服务器端定义的这个监听的Socket指定一个地址及端口(Port),这样客户端才知道待会要连接哪一个地址的哪个端口,为此我们要调用bind()函数,该函数调用成功返回0,否则返回SOCKET_ERROR
int PASCAL FAR bind( SOCKET s, const struct sockaddr FAR *name,int namelen );
数: sSocket对象名;
name
Socket的地址值,这个地址必须是执行这个程式所在机器的IP地址;
namelen
name的长度;

  如果使用者不在意地址或端口的值,那么可以设定地址为INADDR_ANY,及Port0Windows Sockets 会自动将其设定适当之地址及Port (1024 5000之间的值)。此后可以调用getsockname()函数来获知其被设定的值。

  4)监听
  当服务器端的Socket对象绑定完成之后,服务器端必须建立一个监听的队列来接收客户端的连接请求。listen()函数使服务器端的Socket 进入监听状态,并设定可以建立的最大连接数(目前最大值限制为 5, 最小值为1)。该函数调用成功返回0,否则返回SOCKET_ERROR
int PASCAL FAR listen( SOCKET s, int backlog );
数: s:需要建立监听的Socket
backlog
:最大连接个数;
  服务器端的Socket调用完listen()后,如果此时客户端调用connect()函数提出连接申请的话,Server 端必须再调用accept() 函数,这样服务器端和客户端才算正式完成通信程序的连接动作。为了知道什么时候客户端提出连接要求,从而服务器端的Socket在恰当的时候调用accept()函数完成连接的建立,我们就要使用WSAAsyncSelect()函数,让系统主动来通知我们有客户端提出连接请求了。该函数调用成功返回0,否则返回SOCKET_ERROR

int PASCAL FAR WSAAsyncSelect( SOCKET s, HWND hWnd,unsigned int wMsg, long lEvent );
参数: sSocket 对象;
hWnd
:接收消息的窗口句柄;
wMsg
:传给窗口的消息;
lEvent
:被注册的网络事件,也即是应用程序向窗口发送消息的网路事件,该值为下列值FD_READFD_WRITEFD_OOBFD_ACCEPTFD_CONNECTFD_CLOSE的组合,各个值的具体含意为FD_READ:希望在套接字S收到数据时收到消息;FD_WRITE:希望在套接字S上可以发送数据时收到消息;FD_ACCEPT:希望在套接字S上收到连接请求时收到消息;FD_CONNECT:希望在套接字S上连接成功时收到消息;FD_CLOSE:希望在套接字S上连接关闭时收到消息;FD_OOB:希望在套接字S上收到带外数据时收到消息。
  具体应用时,wMsg应是在应用程序中定义的消息名称,而消息结构中的lParam则为以上各种网络事件名称。所以,可以在窗口处理自定义消息函数中使用以下结构来响应Socket的不同事件:  
switch(lParam) 
  {case FD_READ:
     
  break;
case FD_WRITE

   
  break;
   
}

  5)服务器端接受客户端的连接请求

  Client提出连接请求时,Server hwnd视窗会收到Winsock Stack送来我们自定义的一个消息,这时,我们可以分析lParam,然后调用相关的函数来处理此事件。为了使服务器端接受客户端的连接请求,就要使用accept() 函数,该函数新建一Socket与客户端的Socket相通,原先监听之Socket继续进入监听状态,等待他人的连接要求。该函数调用成功返回一个新产生的Socket对象,否则返回INVALID_SOCKET

SOCKET PASCAL FAR accept( SCOKET s, struct sockaddr FAR *addr,int FAR *addrlen );
参数:sSocket的识别码;
addr
:存放来连接的客户端的地址;
addrlen
addr的长度
  6)结束 socket 连接
  结束服务器和客户端的通信连接是很简单的,这一过程可以由服务器或客户机的任一端启动,只要调用closesocket()就可以了,而要关闭Server端监听状态的socket,同样也是利用此函数。另外,与程序启动时调用WSAStartup()函数相对应,程式结束前,需要调用 WSACleanup() 来通知Winsock Stack释放Socket所占用的资源。这两个函数都是调用成功返回0,否则返回SOCKET_ERROR
int PASCAL FAR closesocket( SOCKET s );
数:sSocket 的识别码;     
int PASCAL FAR WSACleanup( void );
数:
二、客户端Socket的操作

  1)建立客户端的Socket


  客户端应用程序首先也是调用WSAStartup() 函数来与Winsock的动态连接库建立关系,然后同样调用socket() 来建立一个TCPUDP socket(相同协定的 sockets 才能相通,TCP TCPUDP UDP)。与服务器端的socket 不同的是,客户端的socket 可以调用 bind() 函数,由自己来指定IP地址及port号码;但是也可以不调用 bind(),而由 Winsock来自动设定IP地址及port号码。

论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics