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 s
);
在程序的最后,需要调用下面的函数,结束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] 下一页 |