| Winsock API 编程介绍下 |
| 作者/管理员 时间/2007-3-16 6:31:00 类别/设计 查看/ |
| 标签:编程 |
|
下面是一个最简单的创建服务器端和客户端的例子: 服务器端的创建 : 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 , IPPROTO_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. 5。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类,就是使用这个模 型. |
| 查看该用户更多文章>> |