版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
(54学时,3814学时程序设计,复习2学时)11章基于套接字的编程TCP/IP应用层位于传输层之上,TCP/IP应用程序需要调用传输层的接口才能实现应用程序之间通信。目前使用最广泛的传输层的应用编程接口是套接字接口〔Socket〕。SocketAPIs1983BerkeleySocketDistribution(BSD)Unix1986AT&T公司引进了另一种不同的网络层编程接口TLI〔TransportLayerInterface〕,1988AT&TTLIXTI〔X/openTransportinterface〕。XTI/TLISocket是用来处理一样任务的不同方法。关于TCP/IPAPIs使用文章与书籍已相当多,本文则是侧重于如何组合使用这些APIsTCP/IP应用程序连接模式设计,并归纳出几种根本应用连接模式。如以以下图:应用层是通过调用传输层接口APIs〔Socket或XTI/TLI〕来与传输层和网络层进展通信的。传输层接口不管是使用何种编程接口,要在两个机器或两个程序之间建立通信,通信双方必需建立相互通信设计模式不全都就无法建立有效的通信连接。socketAPIsTCP/IP应用程序的标准接口,也是影响TCP/IP应用程序通信方式的APIs,不同APIs组合再结合系统调用可以实现不同方式的应用。Sockets支持多种传输层和网络层协议,支持面对连接和无连接的数据传输,允许应用分布式工作。socketsocket,socket表示通信中的一个节点,其可以在socket描述符表示,socketUnix中的文件描述符。bindIPTCPsocket。listensocketsocket,允许该socketsocket允许的最大连接数。acceptsocket描述符,这个的描述符用来建立与客户端的连接。connect:用来建立一个与效劳端的连接。send:发送一个数据缓冲区,类似Unixwritesendto是用在无连接的UDP程序中,用来发送自带寻址信息的数据包。recv:接收一个数据缓冲区,类似UnixreadI。另外recvfromUDP程序中,用来接收自带寻址信息的数据包。close:关闭一个连接客户机/效劳器模型SocketsClientServer交互通信方式来使用的。典型的系统配置是把ServerClient放在另一台机器中,Client连接到Server交换信息。一个socket有一系列典型的大事流在面对连接的Client/Server模型中,ServersocketClient端的恳求。要实现这个恳求,Server端首先Client使用的地址,当地址建立后,ServerClient恳求效劳。当ClientsocketServer后,ClientServer之间就可以进展信息交换。Client/Server是通信程序设计的根本模式。从软件开发的角度讲,TCP/IP应用程Client/ServerClient/Server概念是针对程序内部调用SocketAPI所讲的概念,与针对整个程序甚至针对机器而讲的客户端/效劳器概念有所不同。建立Server需要的APIs有socket,bind,listen,acceptClientAPIsSocket,Connect。在实际应用开发中,同Client和Server的代码,或者多种形式的组合。在实际应用编程中,针对SocketAPIs不同有效组合,结合系统调用可以有多种简洁的设计变化。1、客户机/效劳器模型的工作流程2、效劳器程序特点一般启动后就始终处于运行状态,以等待客户机进程的恳求;使用的端口往往是熟知端口,便于客户机进程连接恳求;一般拥有较多的系统资源,以便准时响应各个客户机进程的恳求;可以并行处理多个客户机进程的恳求,但数目是有确定的限制;IP地址和端口信息。3、客户机程序特点接,得到满足并完成处理后就终止通信连接;放该端口;拥有相对较少的系统资源;在通信时属于主动的一方,需要事先知道效劳器的IP地址和端口信息。套接字概念1、概述在网络中要全局地标识一个参与通信的进程,需要承受三元组:协议、主机IP地址、端口号。要描述两个应用进程之间的端到端的通信关联则需要一个五元组:协议、信源机IP地址、信源应用进程端口、信宿机IP地址、信宿应用进程端口。IP地址和端口号。将两个套接字连接到一起便可以在不同应用进程之间传递数据套接字实现了对网络和传输层协议的封装,为应用进程之间的通信连接的建立、数据传输等通信过程供给了编程界面。2、使用套接字通信示意图基于套接字的通信过程可以描述为:创立/翻开套接字、向套接字收发数据、关闭套接字。3、针对不同的通信需求,在TCP/IP中供给了3种不同套接字类型流套接字〔SOCK_STREAM〕:用于供给面对连接、牢靠的数据传输效劳。该效劳将保证数据能够实现无过失、无重复发送,并按挨次接收。流套接字之所以能够实现牢靠的数据效劳,缘由在于其使用了传输把握协议——TCP。这类套接字中,传输数据之前必需在两个应用进程之间建立一条通信连接,这就确保了参与通信的两个应用进程都是活动并且响应的。当连接TCP层发送数据流,而另一个应用进程便可以接收到相应的数据流,它们不需要知道传输层是如何对数据流进展处理。特别需要留意的是通信连接必需显式建立。该套接字类型适合传输大量的数据,但不支持播送和多播方式。数据报套接字〔SOCK_DGRAM〕:供给了一种无连接的效劳,通信双方不需要建立任何显式连接,数据可以发送到指定的套接字,并且可以从指定的套接字接收数据。该效劳并不能保证数据传输的牢靠性,数据有可能在传输过程中丧失或消灭数据重复,且无法保证挨次地接收到数据。数据报套接字使用UDP进展数据的传输。由于数据包套接字不能保证数据传输的牢靠性,对于有可能消灭的数据丧失状况,需要在程序中做相应的处理。与数据报套接字相比,使用流式套接字是一个更为牢靠的方法,但对于某些应用,建立一个显式连接所导致的系统开销是令人难以接收的,并且数据报套接字支持播送和多播方式。原始套接字〔SOCK_RAW〕:与标准套接字〔标准套接字指的是前面介绍的流套接字和数据报套接字〕的区分在于:原始套接字可以读写内核没有处IP数据包,TCP的数据,数据报套接字只能读取UDP的数据避开TCP/IP处理机制,被传送的数据包可以被直接传送给需要它的应用程序。因此,其主要是在编写自定义底层协议的应用程序时使用,例如各种不同的TCP/IP有用程序〔如ping和arp〕都使用原始套接字实现,也可以用来实现数据包捕获分析等。套接字编程根底从应用编程角度来看,套接字就是TCP/IP网络编程接口的集合,它是应用程序与TCP/IP协议族通信的中间软件抽象层,其中包含了很多函数或例程,程序员可以用它们来开发网络应用程序1、面对连接的客户机/效劳器程序工作模型效劳器进程的五元组建立socket函数确定所使用的协议。bindIP和端口号的绑定,即确定本地IP和端口号。由acceptIP地址和端口号的关联,即确定远程IP和端口号。客户机进程五元组建立socket函数确定所使用的协议。bindIP和端口号的绑定,其中本地IP和端口号既可以显式指定也可以由系统自动确定。由connect函数实现与远程IP地址和端口号的关联,即确定远程IP和端口号。2、无连接的客户机/效劳器程序工作模型在编写无连接客户机/效劳器模型的程序时,与面对连接不同:bindIP地址和端口,而由系统IP地址和端口。IP地址和端口的一方发送数据,即充当客户机进程。connect函数,但它不是用来向通信对方发出建立连接的恳求,只是告知内核并由内核保存,以sendrecv函数。但是作为效劳器的应用进程也必需先启动,否则客户机进程的恳求传不到效劳器进程;中动态建立通信双方的通信连接。3API基于.NetFramework的套接字编程根底1、Winsock接口Windows下网络编程的标准-WindowsSockets 是Windows下得到广泛应用的、开放的、支持多种协议的网络编程接口。从1991年的1.0版到1995年的2.0.8版,经过不断完善并在Intel、Microsoft、Sun、SGI、Informix、Novell等公司的全力支持下,已成为Windows网络编程的事实上的标准。Windows Sockets标准以U.C.Berkeley大学BSDUNIX中流行的Socket接口为范例定义了一套Microsoft Windows下网络编程接口。它不仅包含了人们所生疏的BerkeleySocket 风格的库函数;也包含了一组针对Windows的扩展库函数,以使程序员能充分地利用Windows消息驱动机制进展编程。Windows Sockets标准本意在于供给应应用程序开发者一套简洁的API,并让各家网络软件供给商共同遵守。此外,在一个特定版本Windows的根底上,Windows Sockets也定义了一个二进制接口〔ABI〕,以此来保证应用Windows Sockets API 的应用程序能够在任何网络软件供给商的符合WindowsSockets 协议的实现上工作。因此这份标准定义了应用程序开发者能够使用,并且网络软件供给商能够实现的一套库函数调用和相关语义。遵守这套 WindowsSockets 标准的网络软件,我们称之为Windows Sockets兼容的,而Windows Sockets兼容实现的供给者,我们称之为Windows Sockets 供给者。一个网络软件供给商必需百分之百地实现Windows Sockets 标准才能做到现Windows Sockets 兼容。任何能够与WindowsSockets兼容实现协同工作的应用程序就被认为是具有Windows Sockets接口。我们称这种应用程序为Windows Sockets应用程序。Windows Sockets标准定义并记录了如何使用API与Internet协议族〔IPS,通常我们指的是TCP/IP〕连接,尤其要指出的是全部的Windows Sockets实现都支持流套接口和数据报套接口.应用程序调用Windows Sockets的API实现相互之间的通讯。Windows Sockets又利用下层的网络通讯协议功能和操作系统调用实现实际的通讯工作。2、System.Net.Sockets命名空间〔“://msdn.microsoft/zh-“://msdn.microsoft/zh-cn/library/sb27wehh(v=VS.100).aspx〕NETFramework是用于Windows的托管代码编程模型。它强大功能与技术结合起来,用于构建具有视觉上引人注目的用户体验的应用程序,实现跨技术边界的无缝通信,并且能支持各种业务流程。NETFramework.NETFramework类库。公共语言运行库管理内存、线程执行、代码执行、代码安全验证、编译以及其他系统效劳。这些功能是在公共语言运行库上运行的托管代码所固有的。NETFramework类库是一个与公共语言运行库严密集成的可重用的类型集合。该类库是面对对象的,并供给您自己的托管代码可从中导出功能的类型。这不但使.NETFramework.NETFramework的功能所需要的时间。此外,第三方组件可与.NETFramework中的类无缝集成。NETFramework类库中的System.Net.Sockets命名空间为需要严密把握网络访问的开发员供给了WindowsSockets(Winsock)接口的托管实现。(TcpClient、TcpListenerUdpClientInternetTCPUDP连接的具体信息。)类说明IPv6MulticastOptionIPv6类说明IPv6MulticastOptionIPv6多路播送组的选项值。LingerOptionCloseClose方法之后,假设仍有数据要发送,Socket是否保持连接以及保持多长时间。MulticastOptionMulticastOption包含用于联接和丢弃多路播送组的IPAddress值。NetworkStream供给用于网络访问的根底数据流。SendPacketsElementSocketSendPacketsElement数组中的一个元素。Berkeley套接字接口。SocketAsyncEventArgs表示异步套接字操作。SocketException发生套接字错误时引发的特别。TcpClientTcpListenerUdpClient(UDP)网络效劳。4、Socket类〔Berkeley套接字接口。〕Socket类为网络通信供给了一套丰富的方法和属性。Socket类允许您使用ProtocolType枚举中所列出的任何一种协议执行异步和同步数据传输。Socket类对异步方法遵循.NETFramework命名模式。例如,同步的Receive方法对应于异步的BeginReceiveEndReceive方法。假设应用程序在执行期间只需要一个线程,请使用下面的方法,这些方法适用于同步操作模式。假设当前使用的是面对连接的协议〔如TCP〕,则效劳器可以使用Listen方法侦听连接。Accept方法处理任何传入的连接恳求,并返回可用于与远程主机进展数据通信的Socket。SocketSendReceive方法。假设要指定本地IP地址和端口Listen方法之前先调用Bind方法。假设您期望根底效劳供给程序为您安排可用端口,请使用端口号0。假设期望连接到侦听主机,请调用Connect方法。假设要进展SendReceive方法。假设当前使用的是无连接协议〔如UDP〕,则根本不需要侦听连接。调用ReceiveFrom方法可承受任何传入的数据报。使用SendTo方法可将数据报发送到远程主机。假设要在执行过程中使用单独的线程处理通信,请使用下面的方法,这些方法适用于异步操作模式。假设当前使用的是面对连接的协议〔如TCP〕,则可使用Socket、BeginConnect和EndConnect方法来连接侦听主机。通过使用BeginSendEndSend方法,或者使用BeginReceiveEndReceive方法,可以进展异步数据通信。可以使用BeginAccept和EndAccept处理传入的连接恳求。UDP等无连接协议,则可以使用BeginSendToEndSendTo来发送数据BeginReceiveFromEndReceiveFrom来接收数据报。假设对一个套接字执行多个异步操作,它们不愿定按启动时的挨次完成。当数据发送和数据接收完成之后,可使用ShutdownSocketShutdown之CloseSocket关联的全部资源。Socket类,您可以使用SetSocketOptionSocketGetSocketOption方法来检索这些设置。说明说明假设要编写相对简洁的应用程序,而且不需要最高的性能,则可以考虑使用TcpClient、TcpListenerUdpClientSocket通信供给了更简洁、对用户更友好的接口。5、Socket成员
构造函数名称 说明Socket(SocketInformation)Socket(AddressFamily,SocketType,ProtocolType)名称说明名称说明
DuplicateAndClose返回的指定的值初Socket类的实例。使用指定的地址族、和协议初始Socket类的实例。AcceptAcceptAsyncBeginAccept(Socket,Int32,AsyncCallback,Object)BeginConnect(IPAddress,Int32,AsyncCallback,Object)BeginDisconnectBeginReceive(IList<ArraySegment<Byte>>,SocketFlags,AsyncCallback,Object)BeginReceiveFromBeginReceiveMessageFromBeginSend(IList<ArraySegment<Byte>>,SocketFlags,AsyncCallback,Object)
为建连接创立的Socket。开头一个异步操作来承受一个传入的连接尝试。开头异步操作以承受从指定套接字传入的连接尝试并接收客户端应用程序发送的第一个数据块。开头一个对远程主机连接的异步恳求。IPAddress和端口号指定。开头异步恳求从远程终结点断开连接。Socket中异步接收数据。开头从指定网络设备中异步接收数据。SocketFlags将指定字节数的数据异步接收到数据缓冲区的指定位置,然后存储终结点和数据包信息。将数据异步发送到连接的Socket。BeginSendFile(String,AsyncCallback,Object) UseDefaultWorkerThread标志,fileNameSocket对象。BeginSendToBindCancelConnectAsyncClose
向特定远程主机异步发送数据。Socket与一个本地终结点相关联。取消一个对远程主机连接的异步恳求。Socket连接并释放全部关联的资源。Close(Int32) Socket连接并释放全部关联的资源。Connect(EndPoint)Connect(IPAddress,Int32)
建立与远程主机的连接。建立与远程主机的连接。主机由IP地址和端口号指定。Connect(IPAddress[],Int32) 建立与远程主机的连接。主机由IP地址的数组和端口号指定。Connect(String,Int32) 建立与远程主机的连接。主机由主机名和端口号指定。ConnectAsync(SocketAsyncEventArgs)ConnectAsync(SocketType,ProtocolType,SocketAsyncEventArgs)
开头一个对远程主机连接的异步恳求。开头一个对远程主机连接的异步恳求。DisconnectDisconnectAsyncDispose
关闭套接字连接并允许重用套接字。开头异步恳求从远程终结点断开连接。Socket类的当前实例占用的全部资源。Dispose(Boolean) Socket使用的非托管资源,并可依据需要释放托管资源。DuplicateAndClose 重复目标进程的套接字引用,并关闭此进程的套接字。EndAccept(IAsyncResult) 异步承受传入的连接尝试,并创立的Socket来处理远程主机通信。EndAccept(Byte[],IAsyncResult) 异步承受传入的连接尝试,并创立的Socket对象来处理远程主机通信。此方法返回包含所传输的初始数据的缓冲区。EndAccept(Byte[],Int32,IAsyncResult) 异步承受传入的连接尝试,并创立的Socket对象来处理远程主机通信。此方法返回一个缓冲区,其中包含初始数据和传输的字节数。EndConnectEndDisconnectEndReceive(IAsyncResult)EndReceive(IAsyncResult,SocketError)EndReceiveFrom
完毕挂起的异步连接恳求。完毕挂起的异步断开连接恳求。完毕挂起的异步读取。完毕挂起的异步读取。完毕挂起的、从特定终结点进展异步读取。EndReceiveMessageFrom 完毕挂起的、从特定终结点进展异步读取。此方法还显示有关数据包而不是EndReceiveFrom的更多信息。EndSend(IAsyncResult)EndSend(IAsyncResult,SocketError)EndSendFileEndSendTo
完毕挂起的异步发送。完毕挂起的异步发送。完毕文件的挂起异步发送。完毕挂起的、向指定位置进展的异步发送。Equals(Object) Object是否等于当前的Object〔Object。〕Finalize Socket类使用的可用资源。〔重写Object.Finalize。〕GetSocketOption(SocketOptionLevel,SocketOptionName)GetTypeListenReceive(IList<ArraySegment<Byte>>)
Socket选项的值,表示为一个对象。Type〔继承自Object。〕Socket置于侦听状态。Socket接收数据,将数据存入接收缓冲区列表中。Receive(Byte[]) Socket套接字接收数据,将数据存入接收缓冲区。ReceiveFrom(Byte[],EndPoint) 将数据报接收到数据缓冲区并存储终结点。ReceiveFromAsyncReceiveMessageFrom
开头从指定网络设备中异步接收数据。SocketFlags将指定字节数的数据接收到数据缓冲区的指定位置,然后存储终结点和数据包信息。ReceiveMessageFromAsync 开头使用指定的SocketAsyncEventArgs.SocketFlags将指定字节数的数据异步接收到数据缓冲区的指定位置,并存储终结点和数据包信息。SelectSend(IList<ArraySegment<Byte>>)
确定一个或多个套接字的状态。将列表中的一组缓冲区发送到连接的Socket。Send(Byte[])Send(IList<ArraySegment<Byte>>,SocketFlags)Send(Byte[],SocketFlags)Send(IList<ArraySegment<Byte>>,SocketFlags,SocketError)Send(Byte[],Int32,SocketFlags)
将数据发送到连接的Socket。SocketFlags,将列表中的一组缓冲区发送到连接的Socket。SocketFlags将数据发送到Socket。SocketFlags,将列表中的一组缓冲区发送到连接的Socket。SocketFlags,将指定字节数的数据发送到已连接的Socket。Send(Byte[],Int32,Int32,SocketFlags) SocketFlags,将指定字节数的数据发送到已连接的Socket〔从指定的偏移量开头〕。Send(Byte[],Int32,Int32,SocketFlags,SocketError)
从指定的偏移量开头使用指定的SocketFlags将指定字节数的数据发送SendAsync将数据异步发送到连接的Socket对象。SendFile(String)UseDefaultWorkerThread传输标fileName发送到连接的Socket对象。SendFile(String,Byte[],Byte[],TransmitFileOptions)TransmitFileOptions值,fileName和数据缓冲区发送到Socket对象。SendPacketsAsync将文件集合或者内存中的数据缓冲区以异步方法发送给连接的Socket对象。SendTo(Byte[],EndPoint)将数据发送到指定的终结点。SendToAsync向特定远程主机异步发送数据。SetIPProtectionLevelIP保护级别。SetSocketOption(SocketOptionLevel,SocketOptionName,Boolean)Socket选项设置为指定的Boolean值。ShutdownSocket上的发送和接收。ToString返回表示当前Object的String。〔继。〕页首名称说明名称说明AddressFamilySocket的地址族。Available猎取已经从网络接收且可供读的数据量。BlockingConnected
猎取或设置一个值,该值指示Socket是否处于阻挡模式。猎取一个值,该值指示SocketSendReceive操作时连接到远程主机。DontFragment Boolean值,该值指定Socket是否允许将Internet(IP)数据报分段。EnableBroadcast 猎取或设置一个Boolean值,该值指定Socket是否可以发送或接收播送数据包。ExclusiveAddressUse Boolean值,该值指定Socket是否仅允许一个进程绑定到端口。HandleIsBoundLingerState
Socket的操作系统句柄。猎取一个值,该值指示Socket是否绑定到特定本地端口。猎取或设置一个值,该值指定Socket在尝试发送全部挂起数据时是否延迟关闭套接字。LocalEndPointMulticastLoopback
猎取本地终结点。猎取或设置一个值,该值指定传出的多路播送数据包是否传递到发送应用程序。NoDelay Boolean值,该值指定流Socket是否正在使用Nagle算法。OSSupportsIPv4 指示根底操作系统和网络适配器是否支持Internet4(IPv4)。OSSupportsIPv6 指示根底操作系统和网络适配器是否支持Internet6(IPv6)。ProtocolTypeReceiveBufferSizeReceiveTimeout
Socket的协议类型。猎取或设置一个值,它指定Socket接收缓冲区的大小。猎取或设置一个值,该值指定之后同步Receive调用将超时的时间长度。RemoteEndPoint 猎取远程终结点。SendBufferSizeSendBufferSize猎取或设置一个值,该值指定Socket发送缓冲区的大小。SendTimeout猎取或设置一个值,该值指定之后同步Send调用将超时的时间长度。SocketTypeSocket的类型。SupportsIPv4IPv4支持是否可用并且已启用。SupportsIPv6对某些已过时的TtlSocketInternet(IP)数(TTL)值。UseOnlyOverlappedIO指定套接字是否应仅使用重叠I/O模式。基于tcp的套接字应用编程/tcp的一对一谈天程序。类编程实现,在VirtualStudio2023C#实现。分析:TCP的一对一谈天程序,承受客户机/效劳器模式〔C/S模式〕。1、程序界面:效劳进程、客户端启动客户进程。2、程序流程效劳器端A、初始变量赋值ip地址效劳端口号通讯端点〔IPEndPoint〕(IP地址、端口)套接字〔侦听套接字〔三元组〕和连接套接字〔五元组〕〔5〕接收用的字符串B、效劳端建立套接字〔socket〕〕绑定〔bind〕。D、效劳端开头侦听〔listen〕E、等待连接尝试、建立连接套接字〔Accept〕是堵塞函数,因此承受多线程编程,避开程序被堵塞】F、接收数据〔receive〕【为了屡次接收数据,承受循环】G、发送数据〔send〕H、关闭连接套接字、关闭侦听套接字。退出〔shutdown、close〕客户端ip地址(RemoteIPAddress)(2)效劳端口号(RemotePort)远程通讯端点〔RemoteIPEndPoint〕(IP地址、端口)套接字〔连接套接字〔tcp〕〔5〕接收用的字符串B、建立客户端连接套接字〔socket〕C、并与本机〔通讯端点〕绑定〔bind〕。//客户端在恳求连接〔connect〕之前,可以指定本机的端口,也可以不指定,假设指定则需要绑定〔bind〕//不指定端口,则在连接后,随机指定端口并自动建立localEndPoint。〔本地通讯端点〕d、连接效劳器恳求〔connect〕E、接收数据〔receive〕F、发送数据〔send〕H、关闭连接套接字、关闭侦听套接字。退出〔shutdown、close〕3、编码usingSystem;usingSystem.Collections.Generic;usingSystemponentModel;usingSystem.Data;usingSystem.Drawing;usingSystem.Text;usingSystem.Windows.Forms;usingSystem.Net;usingSystem.Net.Sockets;usingSystem.Threading;usingSystem.Collections;//本程序用于验证基于tcp承受socket类编程实现连接的方法,存在确定问题,//但能够实现连接,学习tcp编程的方法,确定了socket编程的一些问题。//可以在此根底上可以进展进一步功能化。namespaceIPIntegrateUtility.DotNetSockUtility{publicpartialclassTCPChat:Form{//效劳端使用的变量privateintlocalport;//端口privateIPAddressiplocaladdress;//ip地址privateIPEndPointiplocalendpoint;//ip终结点privateSocketserverlistensocket;//效劳器侦听套接字privateSocketserverconnectsocket;//效劳端连接套接字,问题所在,多个连接共用此变量,是本程序不能多连接的缘由之一,stringserverReceivestr;//效劳端接收信息,假设允很多台机器连接,那么这个变量是多连接公用的变量,因此必需留意多线程同步问题,或改用其他方法。//客户端使用的变量privateintremoteport;privateIPAddressipremoteaddress;privateIPEndPointipremoteendpoint;privateSocketclientconnectsocket;//客户机连接套接着stringclientReceivestr;//客户端接收信息publicTCPChat{InitializeComponent;//initialize}#region效劳器端代码privatevoidbnserverstart_Click(objectsender,EventArgse){////initializelocalport=2023;//猎取本机ip地址的方法IPHostEntryiptemphostentry=Dns.GetHostEntry(Dns.GetHostName);foreach(IPAddressipaddressiniptemphostentry.AddressList){if(ipaddress.AddressFamily==AddressFamily.InterNetwork){iplocaladdress=ipaddress;break;}}lbips.Text=iplocaladdress.ToString;//iplocaladdress=IPAddress.Parse(““);//建立EndPoint//iplocalendpoint=newIPEndPoint(iplocaladdress,localport);ipaddress.Any则可以让效劳器侦听全部的网络接口的活动。简洁点说就是就是即可使用本机ip地址,也可使用这样的回环地址了。iplocalendpoint=newIPEndPoint(IPAddress.Any,localport);//1、建立侦听套接字serverlistensocket=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);//看看默认缓冲区大小intrb=serverlistensocket.ReceiveBufferSize;intsb=serverlistensocket.SendBufferSize;//设置Socket选项serverlistensocket.SetSocketOption;try{//2、将套接字与地址端口绑定serverlistensocket.Bind(iplocalendpoint);//3、开头侦听//listen的参数的意思是listen的socket等待队列可以在同一时间内到达的个数,假设填0,它用默认的值〔winsocket1.1为5,2.0为20〕。//listen是告知socket对进来的连接进展侦听,它本身并不会进展任何网络I/O的。也就是说listen本身不会启动堵塞操作,属于非堵塞函数!//而accept,connect,send,recv是堵塞函数。serverlistensocket.Listen(0);//由于accept是堵塞函数,因此最好承受多线程变成,避开程序被堵塞//假设不使用多线程,则由于accept函数的堵塞导致程序不能连续运行。//4、启动后台进程,等待连接,并接收数据ThreadStartserveraccept=newThreadStart(serverAcceptconnect);ThreadsAcceptConnect=newThread(serveraccept);sAcceptConnect.IsBackground=true;sAcceptConnect.Start;}catch{return;}}privatevoidserverAcceptconnect//后台进程,用于建立用户的连接{//while(true) //为了接收多个连接,所以要承受循环。假设只有一个连接,就不用循环。{try{//5、等待连接、建立连接套接字serverconnectsocketserverlistensocket.Accept;if(serverconnectsocket.Connected){//后台进程执行代码//由于窗体进程和本代码不是同一个进程,所以不能用下面的语句直接显示提示信息。//serverdisp.Text=serverdisp.Text+“\r\n“+connentInfo;//假设要在窗体进程中显示信息,则需要使用methodinvoker代理和invoke方法。//使用methodinvoker则代理的函数必需是void的无参函数。MethodInvokerdifferentProcessDispose1=newMethodInvoker(SfirstDispMessege);this.Invoke(differentProcessDispose1);//如何只有一个连接,且不想利用的线程,可以在此直接接收。//否则就需要再次使用线程,不然本线程将被下面的循环中的receive函数堵塞。while(true//假设只接收一次,就不用循环,否则使用循环,且使用循环则外围的循环没有用,循环体始终处于工作状态{byte[]serverReceivebuffer=newbyte[1024];//效劳端接收信息缘由是serverconnectsocket.Available刚开头为0,//所以虽然有数据发送,但由于serverconnectsocket.Available为0,所以没有真正接收,只是把Available改为可接收的数据量,Available改位了0,这样下次接收又会出项上面的状况,//如此导致每循环两次才能接收到一次数据的结果,为此需要修改。//intreceivenumber=serverconnectsocket.Receive(serverReceivebuffer,0,serverconnectsocket.Available,SocketFlags.None);//6、承受数据为保证每次都能接收,只需要使用Receive其他重载函数即可intreceivenumber=serverconnectsocket.Receive(serverReceivebuffer,SocketFlags.None);serverReceivestr=Encoding.Unicode.GetString(serverReceivebuffer,0,receivenumber);MethodInvokerdifferentProcessDispose2=newMethodInvoker(SnextDispMessege);this.Invoke(differentProcessDispose2);}}}catch{return;}}}privatevoidSfirstDispMessege//显示初始联系信息的窗体invoke代码{IPEndPointremoteEP,localEP;IPHostEntryremoteHostentry,localHostentry;stringconnentInfo;
remoteEP=(IPEndPoint)serverconnectsocket.RemoteEndPoint;localEP=(IPEndPoint)serverconnectsocket.LocalEndPoint;remoteHostentry=Dns.GetHostEntry(remoteEP.Address);localHostentry=Dns.GetHostEntry(localEP.Address);connentInfo=remoteHostentry.HostName+“ “+DateTime.Now.ToShortTimeString+“connentInfo=connentInfo+“\r\n“+“remoteinfo:“+remoteEP.Address.ToString+“:“+remoteEP.Port.ToString;connentInfo=connentInfo+“\r\n“+“localinfo:“+localEP.Address.ToString+“:“+localEP.Port.ToString;//serverdisp.Text=serverdisp.Text+“\r\n“+connentInfo;//第一次输出产生空行的原因,serverdisp.Text= connentInfo;}privatevoidSnextDispMessege//显示接收信息的窗体invoke代码{serverdisp.Text=serverReceivestr+“\r\n“+ serverdisp.Text;}privatevoidbnserverSent_Click(objectsender,EventArgse){stringsentmessage=serverInput.Text;if(sentmessage.Trim.Length==0){serverInput.Focus;return;}byte[]sentbuffer=Encoding.Unicode.GetBytes(sentmessage);serverconnectsocket.Send(sentbuffer);serverInput.Text=““;}privatevoidbtServerend_Click(objectsender,EventArgse){serverconnectsocket.Shutdown(SocketShutdown.Both);serverconnectsocket.Close;}#endregion#region客户端执行代码//客户端在恳求连接〔connect〕之前,可以指定本机的端口,也可以不指定,假设指定则需要绑定〔bind〕//不指定端口,则在连接后,随机指定端口并自动建立localEndPoint。privatevoidbnclientstart_Click(objectsender,EventArgse){IPEndPointremoteEP,localEP;IPHostEntryremoteHostentry,localHostentry;stringconnentInfo;remoteport=2023;stringserverip=txIp.Text.Trim;try{ipremoteaddress=IPAddress.Parse(serverip);}catch{//猎取本机ip地址作为远程ip地址,也就是本机客户端访问本机效劳端IPHostEntryiptemphostentry=Dns.GetHostEntry(Dns.GetHostName);foreach(IPAddressipaddressiniptemphostentry.AddressList){if(ipaddress.AddressFamily==AddressFamily.InterNetwork){ipremoteaddress=ipaddress;break;}}//ipremoteaddress=IPAddress.Parse(“28“);}ipremoteendpoint=newIPEndPoint(ipremoteaddress,remoteport);//1、建立客户端套接字clientconnectsocket=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);步连接,
try{
//socket.connect也是堵塞方式,因此也建议承受线程或者使用socoket.beginconnect异//但由于连接会很快得到回应(不能连接也会较快得到回应),程序只有略微了停顿,所以为简洁起见,也可就用connect。//2、恳求效劳器连接clientconnectsocket.Connect((EndPoint)ipremoteendpoint);if(clientconnectsocket.Connected){remoteEP=(IPEndPoint)clientconnectsocket.RemoteEndPoint;localEP=(IPEndPoint)clientconnectsocket.LocalEndPoint;remoteHostentry=Dns.GetHostEntry(remoteEP.Address);localHostentry=Dns.GetHostEntry(localEP.Address);connentInfo=remoteHostentry.HostName+“ “+DateTime.Now.ToShortTimeString+“连接成功!“;connentInfo=connentInfo+“\r\n“+“remoteinfo:“+remoteEP.Address.ToString+“:“+remoteEP.Port.ToString;connentInfo=connentInfo+“\r\n“+“localinfo:“+localEP.Address.ToString+“:“+localEP.Port.ToString;clientDisp.Text=clientDisp.Text+“\r\n“+connentInfo;//第一此显示,原文本框没有数据,“\r\n“导致前面显示一空行//启动客户端接收进程,接收效劳器发送的数据//3、承受效劳器发送数据ThreadStartclientaccept=newThreadStart(clientAcceptconnect);ThreadcAcceptConnect=newThread(clientaccept);cAcceptConnect.IsBackground=true;cAcceptConnect.Start;}}catch{return;}}用线程
privatevoidclientAcceptconnect//客户端接收进程,循环接收且receive为堵塞函数,所以采{while(true){byte[]clientReceivebuffer=newbyte[1024];//客户端接收信息intcreceivenumber=clientconnectsocket.Receive(clientReceivebuffer,SocketFlags.None);clientReceivestr=Encoding.Unicode.GetString(clientReceivebuffer,0,creceivenumber);MethodInvokerdifferentProcessDispose2=newMethodInvoker(CnextDispMessege);this.Invoke(differentProcessDispose2);}}privatevoidCnextDispMessege//显示接收信息的窗体invoke代码{clientDisp.Text=clientDisp.Text+“\r\n“+clientReceivestr;//clientDisp.Text=clientReceivestr;}privatevoidbnclientSent_Click(objectsender,EventArgse){stringsentmessage=clientInput.Text;if(sentmessage.Trim.Length==0){clientInput.Focus;return;}byte[]sentbuffer=Encoding.Unicode.GetBytes(sentmessage);clientconnectsocket.Send(sentbuffer);clientInput.Text=““;}privatevoidbtClientend_Click(objectsender,EventArgse){clientconnectsocket.Shutdown(SocketShutdown.Both);clientconnectsocket.Close;}#endregionprivatevoidTCPChat_Load(objectsender,EventArgse){}}}4、本程序要关注问题、解决方法只能一对一谈天,效劳器不能承受多用户的连接。如何开启多线程。网络通讯中的“堵塞模式”和“非堵塞模式”5、程序的通讯模式ClientServertcp的多客户端对一个效劳端连接的谈天程序。基于UDP的套接字应用编程例子1:基于UDP的应用程序主要承受客户机/效劳器模式,这里实现UPD的谈天程序。类编程实现,在VirtualStudio2023C#实现。本程序首先完成基于UDP谈天程序,承受客户机/效劳器模式〔C/S模式〕。1、程序界面:效劳进程、客户端启动客户进程。2.代码如下usingSystem;usingSystem.Collections.Generic;usingSystemponentModel;usingSystem.Data;usingSystem.Drawing;usingSystem.Text;usingSystem.Windows.Forms;usingSystem.Net;usingSystem.Net.Sockets;usingSystem.Threading;usingSystem.Collections;//本程序用于验证基于udp承受socket类编程实现连接的方法,存在确定问题,//但能够实现连接,学习udp编程的方法,确定了socket编程的一些问题。//可以在此根底上可以进展进一步功能化。namespaceIPIntegrateUtility.DotNetSockUtility{publicpartialclassUDPChat:Form{#region代码1变量//代码1变量privateintlocalport1;//端口1privateIPAddressiplocaladdress1;//ip地址1privateIPEndPointiplocalendpoint1;//ip终结点1privateSocketlocalsocket1;//本地套接字1privateIPEndPointRemoteIpEndPoint1;//远程终结点1stringreceivestr1;//接收信息1#endregion#region代码2变量//代码2变量privateintlocalport2;//端口2privateIPAddressiplocaladdress2;//ip地址2privateIPEndPointiplocalendpoint2;//ip终结点2privateSocketlocalsocket2;//本地套接字2privateIPEndPointRemoteIpEndPoint2;//远程终结点2stringreceivestr2;//接收信息2#endregionpublicUDPChat{InitializeComponent;//initialize}#region代码1privatevoidbnserverstart_Click(objectsender,EventArgse){//initializelocalport1=2023;//猎取本机ip地址的方法IPHostEntryiptemphostentry=Dns.GetHostEntry(Dns.GetHostName);foreach(IPAddressipaddressiniptemphostentry.AddressList){if(ipaddress.AddressFamily==AddressFamily.InterNetwork){iplocaladdress1=ipaddress;break;}}//iplocaladdress1=IPAddress.Parse(““);//显示本地ip及端口localipEP1.Text=iplocaladdress1.ToString.Trim+“:“+localport1.ToString.Trim;//建立EndPoint//iplocalendpoint1=newIPEndPoint(iplocaladdress1,localport1);ipaddress.Any则可以让效劳器侦听全部的网络接口的活动。简洁点说就是就是即可使用本机ip地址,也可使用这样的回环地址了。iplocalendpoint1=newIPEndPoint(IPAddress.Any,localport1);//建立套接字localsocket1=newSocket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);try{}
//将套接字与地址端口绑定localsocket1.Bind(iplocalendpoint1);//设置这一项,将允许使用本地播送地址localsocket1.EnableBroadcast=true;//CreatesanIPEndPointtorecordtheIPAddressandportnumberofthesender.//TheIPEndPointwillallowyoutoreaddatagramssentfromanysource.RemoteIpEndPoint1=newIPEndPoint(IPAddress.Any,0);//由于是堵塞函数,因此最好承受多线程变成,避开程序被堵塞//假设不使用多线程,则由于函数的堵塞导致程序不能连续运行。//启动后台进程,预备接收数据ThreadStartlocalaccept=newThreadStart(localAccept1);Threadacceptdata=newThread(localaccept);acceptdata.IsBackground=true;acceptdata.Start;catch{return;}}privatevoidlocalAccept1//后台进程,用于接收数据{while(true)//假设只接收一次,就不用循环,否则使用循环{byte[]Receivebuffer=newbyte[1024];//接收信息EndPointRemoteEndPoint1=(EndPoint)RemoteIpEndPoint1;intreceivenumber=localsocket1.ReceiveFrom(Receivebuffer,refRemoteEndPoint1);receivestr1=Encoding.Unicode.GetString(Receivebuffer,0,receivenumber);receivestr1=((IPEndPoint)RemoteEndPoint1).Address.ToString+“:“+receivestr1;//确定发送的机器MethodInvokerdifferentProcessDispose1=newMethodInvoker(SnextDispMessege);this.Invoke(differentProcessDispose1);}}privatevoidSnextDispMessege//显示接收信息的窗体invoke代码{serverdisp.Text=serverdisp.Text+“\r\n“+receivestr1;}privatevoidbnserverSent_Click(objectsender,EventArgse){stringsentmessage=serverInput.Text;if(sentmessage.Trim.Length==0){serverInput.Focus;return;}IPAddressremoteip=IPAddress.Parse(tbip1.Text.Trim);intremoteport=int.Parse(tbport1.Text);IPEndPointremoteep=newIPEndPoint(remoteip,remoteport);byte[]sentbuffer=Encoding.Unicode.GetBytes(sentmessage);localsocket1.SendTo(sentbuffer,(EndPoint)remoteep);serverInput.Text=““;}privatevoidbtServerend_Click(objectsender,EventArgse){localsocket1.Shutdown(Socket
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026广东汕头大学医学院实验动物中心劳务派遣人员招聘4人备考题库附答案详解(预热题)
- 2026年上半年成都市温江区面向社会考核招聘副高级及以上职称教师备考题库(7人)有完整答案详解
- 2026广东茂名市职业病防治院(茂名市骨伤科医院)招聘就业见习岗位人员1人备考题库完整参考答案详解
- 2026福建福州职业技术学院诚聘高层次人才备考题库含答案详解(巩固)
- 2026江西省江投老年医养有限公司招聘9人备考题库附答案详解(达标题)
- 2026山东日照市老年大学春季兼职教师招聘备考题库及答案详解(典优)
- 2026福建福州市名厝设计咨询有限公司招聘25人备考题库附答案详解(综合卷)
- 2026四川省国有资产投资管理有限责任公司春季招聘4人备考题库附答案详解(夺分金卷)
- 2026陕西省荣复军人第一医院招聘备考题库及答案详解一套
- 2026湖北武汉市三级医院招聘14人备考题库附参考答案详解(a卷)
- 2026年建筑工程绿色施工实施方案
- 河北省石家庄市2026届高三一模考试英语试题(含答案)
- 2026宁波市外事翻译中心招聘翻译人员1人考试参考题库及答案解析
- 《自我管理(第三版)》中职全套教学课件
- 2026年山东省济南市中考数学模拟试卷
- 欢乐购物街基础达标卷(单元测试)2025-2026学年一年级数学下册人教版(含答案)
- 浆砌石护坡施工方案
- 恐龙种类介绍课件
- 【初中语文】第一单元 群星闪耀(复习课件)语文新教材统编版七年级下册
- 码头防污染培训课件
- 深圳市2025年生地会考试卷及答案
评论
0/150
提交评论