高分请问使用socket进行网络编程问题

zhangjianwen 2002-06-04 05:38:13
请问使用socket进行网络编程的步骤,和相关的函数?谢谢!
...全文
109 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
yahua017 2002-06-04
  • 打赏
  • 举报
回复
wo ye bu si hen dong
lvqh 2002-06-04
  • 打赏
  • 举报
回复
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类,就是使用这个模
型.




batizhou 2002-06-04
  • 打赏
  • 举报
回复
服务器:
socket
bind
listen
accept

客户端:
socket
connect
kui 2002-06-04
  • 打赏
  • 举报
回复
可以选择Windows Sockets API编程模式或MFC(Microsoft Foundation Classes)编程模式,前一种的编程步骤是首先建立广播套按字,然后配置及链接广播套按字,最后使用API函数实现信息收发功能。由于Windows Sockets API的收发函数都是阻塞函数,它们要在操作完成后才能返回及释放程序控制权,为了用好这种编程模式,还得自己编写复杂的阻塞管理程序,所以选用了后一种编程模式比较合适,即MFC编程模式。
在MFC 中, 主要由CASyncSocket 及 CSocket两个类实现对 Windows Socket 的支持, CASyncSocket 从较底层提供 Windows Socket 编程接口。 CSocket 类是 CASyncSocket 类的派生类,它继承了基类的功能并从更高层次上提供 Windows Socket 编程接口,还提供了阻塞管理模式,可利用Carchive类进行同步操作。在这里,我们选用 CASyncSocket 类从较底层支持实时广播系统的数据传输功能,手工编写阻塞管理程序,这样在编程上具有较大的灵活性。

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧