收录日期:2021/02/25 15:55:29 时间:2016/05/10 17:29:50 标签:VCL组件开发及应用
//谁有关于Socket编程的资料,容易上手的那种。

//另外,请讲一讲Socket编程中有那些关键技术。比如说,大数据传送时的消息循环是怎样的?
我对多线程的socket感兴趣,可以一起研究
清华大学出版社出版的w.Richard Stevens写的 unix网络编程
socket 基础知识
 
进程通信的概念最初来源于单机系统,由于每个进程都在各自的地址范围内运行,为了保证两个相互通信的进程之间既不互相干扰,又协调一致的工作,操作系统为进程通信提供了相应设施,如UNIX BSD中的管道(pipe),有名管道(named pipe)和软中断信号(singal),UNIX system V的消息(message)、共享存储区(shared memory)和信号量(semaphore)等,但都局限于用在本机进程之间通信。网间进程通信要解决的是不同主机进程间的通信问题(可把同机进程通信看作其中的特例)。为此,首先要解决的是网间进程标识问题。同一主机上,不同进程可以用进程号(pid)唯一标识。但在网络环境下,各主机独立分配的进程号不能唯一标识该进程。例如主机A赋予某进程号5,在B主机也可以存在5号进程,因此5号进程这句话就没有意义了。其次,操作系统支持的网络协议众多,不同协议的工作方式不同,地址格式也不同。因此,网间进程通信还要解决多重协议的识别问题。为了解决上述问题,TCP/IP协议引入了下列几个概念。

端口

   网络中可以被命名和寻址的通信端口是操作系统可分配的一种资源。按照OSI七层协议的描述,传输层与网络层最大的区别是传输层提供进程通信能力。从这个意义上讲,网络通信的最终地址就不仅是主机地址了,还包括可以描述进程的某种标识。为此TCP/IP协议提出了协议端口的概念,用于标识通信的进程。

   端口是一种抽象的软件结构,包括一些数据结构和I/O缓冲区。应用程序即进程通过系统调用与某端口建立连接(binding)后,传输层传给该端口的数据都被相应的进程所接收,相应进程发给传输层的数据都从该端口输出。在TCP/IP协议的实现中,端口操作类似于一般的I/O操作,进程获取一个端口,相当于获取本地唯一的I/O文件,可以用一般的读写原语访问。

   类似于文件描述符,每个端口都拥有一个叫端口号的整数描述符,以区别不同端口。由于TCP/IP传输层的两个协议TCP和UDP是两个完全独立的软件模块,因此各自的端口号也相互独立。如TCP有一个255号端口,UDP也可以有一个255号端口,两者并不冲突。

   端口号的分配是一个重要问题,有两种基本分配方式:第一种叫全局分配这是一种集中分配方式,由一个公认的中央机构根据用户需要尽行统一分配,并将结果公布于众,第二种是本地分配,又称动态连接,即进程需要访问传输层服务时,向本地操作系统提出申请,操作系统返回本地唯一的端口号,进程再通过合适的系统调用,将自己和该端口连接起来(绑定)。TCP/IP端口号的分配综合了两种方式。TCP/IP将端口号分为两部分,少量的作为保留端口,以全局方式分配给服务进程。因此,每一个标准服务器都拥有一个全局公认的端口叫周知口,即使在不同的机器上,其端口号也相同。剩余的为自由端口,以本地方式进行分配。TCP和UDP规定,小于256的端口才能
作为保留端口。

地址

   网络通信中的两个进程分别在两个不同的机器上。在互连网络中,两台机器可以位于不同的网络,这些网络通过网际互连设备(网关,网桥,路由器)连接。因此需要三级寻址。

   1。某一主机与多个网络相连,必须指定一特定网络地址;
   2。网络上美一台主机应有其唯一的地址;
   3。美一主机上的每一进程应有在该主机上的唯一标识。

   主机地址就是IP啦,不必多说。进程唯一标识符是十六位整数端口号。网络字节顺序不同的计算机存放多字节值的顺序不同,有的机器在起始地址存放低位字节,有的则相反。为保证数据的正确性,在网络协议中需指定网络字节顺序。TCP/IP协议使用16位整数和32位整数的高价先存格式,他们均含在协议的头文件中。

连接

   两个进程间的通信链路称为连接。连接在内部表现为一些缓冲区和一组协议机制,在外部表现出比无连接高的可靠性。

半相关

   综上所述,网络中用一个三元组可以在全局中唯一标是一个进程:
     (协议,本机地址,本地端口号)
这样一个三元组,叫做一个半相关,他指定连接的每半部分。

全相关

   一个完整的网间进程通信需要有两个进程组成,并且只能使用同一种高层协议。也就是说TCP和UDP没法通信。因此一个完整的网间进程通信需要一个五元组来标识:
   (协议,本机地址,本地端口号,远地地址,远地端口号)
这样一个五元组叫做一个全相关。

客户机/服务器模式

   在TCP/IP网络应用中,通信的两个进程相互作用的主要模式是客户机/服务器模式,即客户端向服务器发出请求,服务器接收到请求后提供相应的服务客户机/服务器模式的建立基于以下两点:首先,建立网络的起因是网络中软、硬件资源、运算能力和信息不均等,需要共享,从而造就拥有众多资源的主机提供服务,资源较少的客户请求服务这一非对等作用。其次,网间进程通信完全是异步的,相互通信的进程间既不存在父子关系,又不共享内存缓冲区,因此需要一种机制为希望通信的进程间建立一种联系,为二者的数据交换提供同步,这就是基于客户机/服务器模式的TCP/IP。

   客户机/服务器模式在操作过程中采取的是主动请求方式:

   首先服务器方要启动,并根据请求提供相应服务:
   1。打开一通信通道并告知本地主机,它愿意在某一公认地址端口上(周知口,如http为80)接受客户请求。
   2。等待客户请求到达该端口。
   3。接收到重复服务请求,处理该请求并发送应答信号。接收并发服务请求,要激活一新进程来处理这个客户请求。新进程处理此客户请求,并不需要对其他请求做出应答。服务完成后,关闭此新进程与客户的通信链路,并终止。
   4。返回第二步,等待另外的客户请求
   5。关闭服务器。

   客户方:
   1。打开一通信通道,并连接到服务器所在主机的特定端口。
   2。向服务器发出服务请求报文,等待并接收应答;继续提出请求。
   3。请求结束后关闭通信通道并终止。
   从上面的描述过程可知:
   1。客户与服务器进程的作用是非对称的。因此编码不同。
   2。服务进程一般是先于客户请求启动的。只要系统运行,该进程一直存在,直到正常终止或者强迫终止。

套接字SOCKET和perl的socket编程

   在UNIX世界中,网络应用编程界面有两类:BSD的套接字SOCKET和SYSTEM V的TLI.由于Sun公司采用了支持TCP/IP的BSD系统,TCP/IP的应用有了更大发展其网络应用编程界面Socket在网络编程中已成为标准。并且也早已经进入了MS的世界。

   TCP/IP的Socket提供下列三种类型的套接字

   1。流式套接字(SOCKET_STREAM)

   提供了一个面向连接,可靠的数据传输服务,数据无差错,无重复的发送且按发送顺序接收。内设流量控制,避免数据流超限;数据被看作是字节流,无长度限制。FTP协议即采用流式套接字。

   2。数据报式套接字(SOCKET_DGRAM)

   提供了一个无连接服务。数据包以独立包形式被发送,不提供无错保证,数据可能丢失或重复,并且接收顺序无序。网络文件系统NFS使用数据报式套接字。

   3。原始式套接字(SOCKET_RAW)

   该接口允许对较低层次协议,如IP、ICMP直接访问。常用于检验新的协议实现或访问现有服务中配置的新设备。

基本套接字调用

   创建套接字--socket();
   绑定本机端口--bind();
   建立连接--connect(),accept();
   侦听端口--listen();
   数据传输--send(),recv();
   输入/输出多路复用--select();
   关闭套接字--closesocket();

   不论何种语言,和socket打交道都是这一组调用只是在格式上有一点点差别。我只使用过c和perl,再加上这里又不让出现与perl无关的东西,那下面就主要讨论PERL的socket编程啦:

创建建套接字:
socket(SOC_VARIABLE,DOMAIN_FLAG,connectType,num) #相应的C语言调用为so
ckid=socket(af,type,protocol)
参数含义如下:
SOC_VARIABLE是用于建立套接的句柄,相当于c里面的sockid号;
DOMAIN_FLAG叫域标记,在C里相当于af--address family,地址族。地址族和域是一个概念,其实就是平常所说的域。UNIX支持的域类型有
  AF-UNIX; UNIX内部地址
  AF-INET; TCP/IP地址
  AF-NS; Xerox NS地址
  AF-APPLETALK; Apple的Appletalk地址
而dos/windows支持的域地址族只有AF-INET.所以大部分的socket编程都只用到它。
connectType(c里的type)就是前面所说的三种socket类型。
num相当于c里面的protocol那大家一看就明白了这是协议号,用来指定SOCKET请求所希望的协议,这个参数不一定起作用,当前两个参数可以确定协议时可以取值为零。
所以,一个完整的PERL的建立socket如下 
socket(THESCK,AF-INET,SOCKET_STREAM,getprotocolbyname('tcp'));
#c语言: int sockid;
# sockid = socket(AF-INET,SOCKET_STREAM,0); 
 


、Delphi与Socket 

  计算机网络是由一系列网络通信协议组成的,其中的核心协议是传输层的TCP/IP和 

UDP协议。TCP是面向连接的,通信双方保持一条通路,好比目前的电话线,使用telnet 

登陆BBS,用的就是TCP协议;UDP是无连接的,通信双方都不保持对方的状态,浏览器访 

问Internet时使用的HTTP协议就是基于UDP协议的。TCP和UDP协议都非常复杂,尤其是T 

CP协议,为了保证网络传输的正确性和有效性,必须进行一系列复杂的纠错和排序等处 

理。 

  Socket是建立在传输层协议(主要是TCP和UDP)上的一种套接字规范,最初是由美国 

加州Berkley大学提出,它定义两台计算机间进行通信的规范(也是一种编程规范),如 

果说两台计算机是利用一个"通道"进行通信,那么这个"通道"的两端就是两个套接字。 

套接字屏蔽了底层通信软件和具体操作系统的差异,使得任何两台安装了TCP协议软件和 

实现了套接字规范的计算机之间的通信成为可能。 

  微软的Windows Socket规范(简称winsock)对Berkley的套接字规范进行了扩展,利 

用标准的Socket的方法,可以同任何平台上的Socket进行通信;利用其扩展,可以更有 

效地实现在Windows平台上计算机间的通信。在Delphi中,其底层的Socket也应该是Win 

dows的Socket。Socket减轻了编写计算机间通信软件的难度,但总的说来还是相当复杂 

的(这一点在后面具体会讲到);Inprise在Delphi中对Windows Socket进行了有效的封 

装,使得用户可以很方便地编写网络通信程序。下面我们实例解读在Delphi中如何利用 

Socket编写通信程序。 

二、利用Delphi编写Socket通信程序。 

  下面是一个简单的Socket通信程序,其中客户机和服务机是同一个程序,当客户机 

(服务器)在一个memo1中输入一段文字然后敲入回车,该段文字就可以显示在服务器( 

客户机)的memo2中,反之亦成立。具体步骤如下: 

  1、新建一个form,任意命名,不妨设之为chatForm;放上一个MainMenu(在Standa 

rd栏中),建立ListenItem、ConnectItem、Disconnect和Exit菜单项;在从Internet栏 

中选择TServerSocket、TClientSocket添加到chatForm中,其中把TClientSocket的名字 

设为ClientSocket, port设为1025,默认的active为false;把TServerSocket的名字设 

为ServerSocket,port设为1025,默认的active为false,其他的不变;再放入两个mem 

o,一个命名为memo1,另外一个命名为memo2,其中把memo2的color设置为灰色,因为主要 

用来显示对方的输入。下面我们一边编写代码一边解释原因。 

  2、双击ListemItem。写入如下代码: 

procedure TChatForm.ListenItemClick(Sender: TObject); 

begin 

ListenItem.Checked := not ListenItem.Checked; 

if ListenItem.Checked then 

begin 

ClientSocket.Active := False; 

ServerSocket.Active := True; 

end 

else 

begin 

if ServerSocket.Active then 

ServerSocket.Active := False; 

end; 

end; 

  该程序段的说明如下:当用户选择ListemItem时,该ListenItem取反,如果选中的 

话,说明处于Listen状态,读者要了解的是:listen是Socket作为Server时一个专有的 

方法,如果处于listen,则ServerSocket设置为活动状态;否则,取消listen,则关闭S 

erverSocket。实际上,只有用户一开始选择该菜单项,表明该程序用作Server。反之, 

如果用户选择ConnectItem,则必然作为Client使用。 

  3、双击ConnectItem,敲入以下代码。 

procedure TChatForm.ConnectItemClick(Sender: TObject); 

begin 

if ClientSocket.Active then ClientSocket.Active := False; 

if InputQuery('Computer to connect to', 'Address Name:', Server) then 

if Length(Server) > 0 then 

with ClientSocket do 

begin 

Host := Server; 

Active := True; 

ListenItem.Checked := False; 

end; 

end; 

  这段程序的主要功能就是当用户选择ConnectItem菜单项时,设置应用程序为客户机 

,弹出input框,让用户输入服务器的地址。这也就是我们不一开始固定ClientSocket的 

host的原因,这样用户可以动态地连接不同的服务器。读者需要了解的是主机地址只是 

Socket作为客户机时具有的一个属性,Socket作为服务器时"一般"不用地址,因为它同 

本机绑定。 

  4、在memo1的keydown方法中写入如下代码: 

procedure TChatForm.Memo1KeyDown(Sender: TObject; var Key: Word; 

Shift: TShiftState); 

begin 

if Key = VK_Return then 

if IsServer then 

ServerSocket.Socket.Connections[0].SendText(Memo1.Lines[Memo1.Lines.Count - 

1]) 

else 

ClientSocket.Socket.SendText(Memo1.Lines[Memo1.Lines.Count - 1]); 

end; 

  该段代码的作用很明显,就是开始发消息了。其中如果是Server的话,它只向第一 

个客户机发消息,由于一个服务器可以连接多个客户机,而同客户机的每一个连接都由 

一个Socket来维持,因此ServerSocket.Socket.Connnections数组中存储的就是同Clie 

nt维持连接的Socket。在标准Socket中,服务器方的Socket通过accept()方法的返回值 

获取维持同客户机连接的Socket,而发送、接受消息的方法分别为send(sendto)和recv( 

recvfrom), Delphi对此进行了封装。 

  5、其余代码的简要介绍。 

procedure TChatForm.ServerSocketAccept(Sender: TObject; 

Socket: TCustomWinSocket); 

begin 

IsServer := True; 

end; 

  ServerSocket的Accept方法,当客户机第一次连接时完成,通过其参数可以认为, 

它是在标准的accept方法后执行的,因为有TCustomWinSocket这个参数类型,它应该是 

标准Server方Socket的返回值。 

procedure TChatForm.ClientSocketRead(Sender: TObject; 

Socket: TCustomWinSocket); 

begin 

Memo2.Lines.Add(Socket.ReceiveText); 

end; 

procedure TChatForm.ServerSocketClientRead(Sender: TObject; 

Socket: TCustomWinSocket); 

begin 

Memo2.Lines.Add(Socket.ReceiveText); 

end; 

  这两段代码分别是服务器方和客户机方在收到对方的消息时,由Delphi触发的,作 

用是在memo2中显示收到的消息。其中,ClientSocketRead中的Socket实际上就是Socke 

t本身,而在ServerSocketClientRead中的Socket实际上是ServerSocket.Socket.Conne 

ction[]中的某个Socket。不过在Delphi中,对服务器方的Socket进行了有效的封装。 

procedure TChatForm.ServerSocketClientConnect(Sender: TObject; 

Socket: TCustomWinSocket); 

begin 

Memo2.Lines.Clear; 

end; 

procedure TChatForm.ClientSocketDisconnect(Sender: TObject; 

Socket: TCustomWinSocket); 

begin 

ListenItemClick(nil); 

end;            单。其中ServerSocketClientConnect在ServerSocket收到一个新的连 

接时触发。而ClientSocketDisconnect在ClientSocket发出Disconncet时触发。 

procedure TChatForm.Exit1Click(Sender: TObject); 

begin 

ServerSocket.Close; 

ClientSocket.Close; 

Close; 

end; 

procedure TChatForm.Disconnect1Click(Sender: TObject); 

begin 

begin 

ClientSocket.Active := False; 

ServerSocket.Active := True; 

end; 

  第一段为关闭应用程序。在标准Socket中,每个Socket在关闭时,必须调用closes 

ocket()方法,否则系统不会释放资源。而在ServerSockt.Close和ClientSocket.Close 

中,系统内部肯定调用了closesocket()方法。 

三、标准Socket与Delphi中的Socket。 

标准的Socket的应用程序框架如下: 

Server方: Socket()[ 新建一个Socket]--Bind()[ 同服务器地址邦定 ]--Listen 

() --Accept()--block wait--read()[接受消息,在windows平台中,方法为sen 

d(TCP),或者是sendto(UDP)]--处理服务请求--Write()[发送消息,在windows平台 

中,方法为send(TCP), 或者为sendto(UDP)。 

Client方相对简单:Socket()--Connect()[通过一定的port连接特定的服务器,这是 

与服务器建立连接]--Write()--Read()。 

  Socket可以是基于TCP的,也可以是基于UDP,同时Socket甚至建立在其他的协议,比 

如IPX/SPX,DECNet等。在新建一个Socket时,可以指定新建何类Socket。Bind()用来同 

服务器的地址邦定,如果一个主机只有一个IP地址,实际上邦定的作用就相对多余了。 

Listen()开始监听网络,Accept()用于接受连接,其返回值是保持同客户机联系的Sock 

et。 

  在Delphi中,对于Windows中的Socket进行了有效的封装。在Delphi中,按其继承关 

系,可以分层两类: 

一、TComponent--TAbstractSocket--TCustomSocket--TCustomServerSocket-- 

TServerSocket 

TComponent--TAbstractSocket--TCustomSocket--TClientSocket 

二、直接从TObject继承过来: 

TObject--TCustomWinSocket--TServerWinSocket 

TObject--TCustomWinSocket--TClientWinSocket 

TObject--TCustomWinSocket--TServerClientWinSocket 

  可以看出第一类建立在TCustomSocket基础上,第二类建立在TCustomWinSocket的基 

础上。第一类建立在TComponet的基础上,第二类直接构建在TObject基础上。因此如果 

用户非常熟悉Socket并且想要编写控制台程序时,可以使用TCustomWinScoket类。 

  同uses中可以看出,它们都在ScktComp.pas中实现,而在schtComp.pas中,则包含 

了winsock.pas文件,如果继续深
网上多去找找,去www.google.com上去搜索

java围棋程序 VC2010中CString型的怎样转化成int的? 数据窗口 如何获取某几列的修改前和修改后的数据? 一个DLL 需要被2个VC EXE程序同时调用的问题? php正则表达式问题 myeclipse部署项目之后启动tomcat时说配置发生错误,请确认的优先领域和提示,无法连接到虚拟机VM,求大神,求救命,求教导 武汉 2年软件开发经验能给多少 IT界抬高房价 Annotation进行声明式事务管理不能获得session,麻烦了 关于int (*p)[5]的情况 运行栈溢出,求大神解决啊 构造函数 在校研究生的迷茫,不知所措 下面程序为何编译不过 c# MFC中怎么实现对postgreSQL数据库的操作 【已处理】申请临时删除已经上传的资源 弱弱的问一句,发布功能 一剑飘红的C语言教程 合格率计算 猫猫,生日快乐呦~~~~~~~ 求助 C# 数据查询流程图控件 【菜鸟求教】 猫猫,Happy Birthday~~~~~~~ 各位c++的大神来看,此题怎么解 求教helixserver+producer实现实时播出的具体配置 計算總和 JAVA P2P实现即时通信的思路 乱码噢...愁银...怎么办啊! MySql驱动问题