打印本文 打印本文 关闭窗口 关闭窗口
ServerSocket,ClientSocket控件源码阅读笔记
作者:武汉SEO闵涛  文章来源:敏韬网  点击数7766  更新时间:2009/4/23 18:28:00  文章录入:mintao  责任编辑:mintao
p;        
  const struct sockaddr FAR*  name
  int namelen                        
);

函数里的参数和bind()一个,不多说了,函数成功时返回0,否则返回SOCKET_ERROR。

服务端在Bind之后,调用下面函数进行监视。

int listen (
  SOCKET s,    
  int backlog  
);

其中backlog是可以建立的最大连接数,如果值设为SOMAXCONN,将由Socket的服务提供商设定一个合理的值,这个值不确定。

函数成功时返回0,否则返回SOCKET_ERROR。

当客户端连接服务端,服务端调用下面函数接收客户的请求,并向客户机发送应答信息

SOCKET accept (
  SOCKET s,                   
  struct sockaddr FAR* addr
  int FAR* addrlen            
);

其中中addr是用来保存客户机地址信息的指针

Addrlen是addr的长度一般是Sizeof(addr)

如果函数成功,则返回一个Socket,这个Socket才是与客户实际通信的套接字,原来的那个Socket继续监视其他客户端的连接

以下几个是用个服务机和客户机通信的函数,
int send (SOCKET s,const char FAR * buf, int len,int flags );
在面向连接的情况下发送数据
int recv (SOCKET s, char FAR* buf,  int len, int flags );
在面向连接的情况下接收数据
另外还有sendto和recvfrom用于无连接情况,具体查MSDN
其中Buf是发送或接收的缓冲区,Len是缓冲区的大小,Flags是网络呼叫产生方式标志,值可以为0,MSG_DONTROUTE或 MSG_OOB用途具体看MSDN。
通信完毕后,需要关闭Socket,函数声明如下:
int closesocket (
  SOCKET
);
在程序的最后,需要调用下面的函数,结束WinSock DLL
int  WSACleanup (void);

函数成功时返回0,否则返回SOCKET_ERROR。

 
下面开始TServerSockett和TClientSocket的原代码阅读:

不过在分析之前,先要明白,对于WinSock的封装其实是由ScktComp单元的几个类一起完成的,它们的关系是:

TServerSocket继承于TCustomServerSocket

TCustomServerSocket继承于TCustomSocket

TCustomSocket继承于TAbstractSocket而TAbstractSockeet的上级则是TComponent了

TClientSocket继承于TCustomSocket

另外还有几个类:

TServerWinSocket和TClientWinSocket以及TServerClientWinSocket继承TCustomSocket

它们才是真正封装Socket的类。作为上面提到的类的成员存在

此外还有几个用于阻塞式传输的类。这里就忽略不讲了,以后有机会再补上来吧。

 

以ServerSocket和ClientSocket的一次操作流程来跟踪它们的源代码,看看他们是怎么样封WinSocket的。以非阻塞方式来例子。

 

1.  ServerSocket要创建,构造函数如下:

(11

constructor TServerSocket.Create(AOwner: TComponent);

begin

  inherited Create(AOwner);

  FServerSocket := TServerWinSocket.Create(INVALID_SOCKET);

  InitSocket(FServerSocket);

  FServerSocket.ThreadCacheSize := 10;

end;

inherited Create(AOwner);是继承自TComponent的构造函数。

接下来创建它的一个成员,这是一个TServerWinSocket的对象,这个才是真正封装SocketApi的类,等一个讨论它。事实上这个构造函数继承自它的父类TCustomServerSocket

接下来调用InitSocket(FServerSocket);这是ServerSocket的祖先类TAbstractSocket的一个方法,传入参数是成员FserverSocket完成的功能是将ServerSocket的事件指针指向TServerWinSocket的事件,使其能处理Socket触发的事件。

最后,设置FServerSocket允许连接的线程数,这里为10。

 

好,现在回过头来看看FServerSocket := TServerWinSocket.Create(INVALID_SOCKET);做了什么:

(111

constructor TServerWinSocket.Create(ASocket: TSocket);

begin

  FConnections := TList.Create;

  FActiveThreads := TList.Create;

  FListLock := TCriticalSection.Create;

  inherited Create(ASocket);

  FAsyncStyles := [asAccept];

end;

首先创建两个TList对象,一个是FConnections,代表各个处理客户连接的Socket,它对应于属性:property Connections[Index: Integer]: TCustomWinSocket,你可以通过这个属性对各个客户连接进行操作。FActiveThreads 管理由Connections 数组确定的的客户端连接线程TServerClientThread,它对应的属性是ActiveThreads,这个是只读属性,返回当前正在使用的TServerClientThread对象的个数。接下来创建互斥量对象,用于线程同步的处理。

到这里又调用其父类的构造函数,传递的参数就是ServerSocket给的值INVALID_SOCKET,(想想上面提到的这个值的意义)

好,再继续跟踪,到其父类的构造函数去看一下,我们这时应该保留一个问题,按照WinSock的编程模式,刚开始应该是初始化Winsock.DLL,并调用绑定监听函数,这些API是什么在地方被调用呢?

(1111

constructor TCustomWinSocket.Create(ASocket: TSocket);

begin

  inherited Create;

  Startup;

  FSocketLock := TCriticalSection.Create;

  FASyncStyles := [asRead, asWrite, asConnect, asClose];

  FSocket := ASocket;

  FAddr.sin_family := PF_INET;

  FAddr.sin_addr.s_addr := INADDR_ANY;

  FAddr.sin_port := 0;

  FConnected := FSocket <> INVALID_SOCKET;

end;

首先调用TObject的构造函数,

再调用Sartup;分析完这个函数再看里面的代码,这里可以猜测它里面会调用WSAStartup函数。

接下来看到从ServerSocket传过来的参数指定给了TCustomWinSocket的成员,还有下面几个成员的设置,可以肯定,这里是对Socket进行初始化,结合开头所讲的知识,再看看源代码。应该不难理解了吧。

再看看Startup的源码:

(11111

上一页  [1] [2] [3] [4] [5] [6] [7] [8] [9]  下一页

打印本文 打印本文 关闭窗口 关闭窗口