Delphi网络编程
我们知道网络层,可以实现两个主机之间的通信。但是这并不具体,因为,真正进行通信的实体是在主机中的进程,是一个主机中的一个进程与另外一个主机中的一个进程在交换数据。IP协议虽然能把数据报文送到目的主机,但是并没有交付给主机的具体应用进程。而端到端的通信才应该是应用进程之间的通信。
官方文档:http://docwiki.embarcadero.com/RADStudio/Sydney/en/Writing_Internet_Applications_Index
官方案例:http://docwiki.embarcadero.com/CodeExamples/Sydney/en/Chat_Room_Socket_(Delphi)
# 继承体系
Delphi 中自带两套TCP Socket 组件:Indy Socket 组件(IdTcpClient和IdTcpSerever)和Delphi 原生的TCP Socket 组件(ClientSocket和ServerSocket)在Delphi中,对于Windows中的Socket进行了有效的封装。在Delphi中,按其继承关系,可以分层两类:
TComponent--TAbstractSocket--TCustomSocket--TCustomServerSocket--TServerSocket
TComponent--TAbstractSocket--TCustomSocket--TClientSocket
直接从TObject继承过来:
TObject--TCustomWinSocket--TServerWinSocket
TObject--TCustomWinSocket--TClientWinSocket
编写控制台程序时,可以使用TCustomWinScoket类,同uses中可以看出,它们都在ScktComp.pas中实现,而在schtComp.pas中,则包含了winsock.pas文件,如果继续深入winsock文件,在其中可以发现所有的Windows Socket的基本方法。
Delphi7 里面已经没有这两个组件了。取而代之的是两个INDY套接字组件(IdTCPClient与IdTCPServer)TServerSocket和TClientSocket两个组件已经被Borland宣布过时了,虽然他们还可以用,但Borland建议使用相应的Indy组件代替。
以上文字摘自《Delphi7入门与提高》
备注:http://docwiki.embarcadero.com/RADStudio/Sydney/en/Installing_Socket_Components
# Indy Socket 组件
官方地址:https://www.indyproject.org/download/
原文:Indy is an open source client/server communications library that supports TCP/UDP/RAW sockets, as well as over 100 higher level protocols including SMTP, POP3, IMAP, NNTP, HTTP, FTP, and many more. Indy is written in Delphi but is available for C++Builder, Delphi, FreePascal, .NET, and Kylix.
译文:Indy是一个开放源代码客户端/服务器通信库,它支持TCP / UDP / RAW套接字以及100多个更高级别的协议,包括SMTP,POP3,IMAP,NNTP,HTTP,FTP等。 Indy用Delphi编写,但可用于C ++ Builder,Delphi,FreePascal,.NET和Kylix。
# TCP建立连接的过程
最开始的时候客户端和服务器都是处于CLOSED状态。主动打开连接的为客户端,被动打开连接的是服务器。
三次握手的具体过程阐述如下:
客户端主动与服务器联系,TCP首部控制位中的SYN设置为1,发送带有SYN的TCP段,并把初始序号告诉对方。
服务器端收到带有SYN的报文,记录客户端的初始序号,选择自己的初始序号,设置控制位中的SYN和ACK。因为SYN占用一个序号,所以确认序号设置为客户端的初始序号加1,对客户端的SYN进行确认。
服务器端的报文到达客户端,客户端设置ACK控制位,并把确认号设为服务器的初始序号加1,以确认服务器的SYN报文段,这个报文只是确认信息,告诉服务器已经成功建立了连接
# 函数详解
学习嘛还是从底层开始,所以这次学习和就研究的就是利用win32API实现简单的端到端的通讯,涉及到的函数如下:
//引用的单元
uses Winapi.WinSock2, ScktComp;
2
3
# 初始化
function WSAStartup(wVersionRequired: word; var WSData: TWSAData): Integer; stdcall;
参数说明:
参数名称 | 作用 |
---|---|
wVersionRequired | 要求使用Winsock的最低版本号 |
WSData | 这个结构体中返回WinSock库的一些信息,如版本号,监听队列的大小 |
返回值:
当函数成功调用时返回0,失败时返回非0的值
# 生成socket
function socket(af, Struct, protocol: Integer): TSocket; stdcall;
参数说明:
参数名称 | 作用 |
---|---|
af | 地址家族(通常使用:AF_INET) |
Struct | socket的种类,SOCK_STREAM : 用于TCP协议,SOCK_DGRAM : 用于UDP协议 |
protocol | 所使用的协议 |
返回值:
当函数成功调用时返回一个新的SOCKET
失败时返回INVALID_SOCKET
# 绑定IP和端口号
function bind(s: TSocket; var addr: TSockAddr; namelen: Integer): Integer; stdcall;
参数说明
参数名称 | 作用 |
---|---|
s | 指向用Socket函数生成的Socket |
addr | 这个结构体用于指定服务器端IP、端口等信息 |
namelen | 结构体的长度 |
返回值
当函数成功调用时返回0
调用失败时返回 SOCKET_ERROR
# 等待客户端
function accept(s: TSocket; addr: PSockAddr; addrlen: PInteger): TSocket; stdcall;
参数说明:
参数名称 | 作用 |
---|---|
s | 是一个限定套接字,它处在监听模式 |
addr | 有效的TSockAddr结构的地址 |
namelen | 结构的长度 |
返回值
当函数成功调用时返回客户端的Socket对象
失败时返回INVALID_SOCKET
# 发送数据
function send(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
参数说明:
参数名称 | 作用 |
---|---|
s | 参数是已建立连接的套接字 |
Buf | 字符缓冲区,区内包含即将发送的数据 |
len | 指定即将发送的缓冲区内的字符数 |
flags | flags可为0、MSG_DONTROUTE或MSG_OOB |
返回值
当函数成功调用时返回发送的字节数
失败时返回SOCKET_ERROR