C#socket编程从入门到精通_第1页
C#socket编程从入门到精通_第2页
C#socket编程从入门到精通_第3页
C#socket编程从入门到精通_第4页
C#socket编程从入门到精通_第5页
已阅读5页,还剩21页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、讲Socket编程前,先来看几个常用的类和方法,相信这些东西可以事半功倍。一、IP地址操作类1、IPAddress类在该类中有一个Parse(方法,可以把点分的十进制IP表示转化成IPAddress类IPAddress提供4个只读字段 Any 用于代表本地系统可用的任何IP地址 Broadcase 用于代表本地网络的IP广播地址 Loopback 用于代表系统的回送地址 None 用于代表系统上没有网络接口其中IPAddress.Any常用来表示本机上所有的IP地址,这对于socket服务进行侦听时,方便使用,不用对每个IP进行侦听了。而IPAddress.Broadcase可用来UDP的IP

2、广播。2、IPEndPoint类我们可以通过2种构造方法来创建IPEndPoint类:a、IPEndPoint(long address, int portb、IPEndPoint(IPAddress address, int port四个属性:Address AddressFamily Port MaxPort MinPort IPEndPoint其实就是一个IP地址和端口的绑定,可以代表一个服务,用来Socket通讯。二、DNS相关类DNS类有四个静态方法,来获取主机DNS相关信息,1、GetHostName(通过Dns.GetHostName(可以获得本地计算机的主机名2、GetHost

3、ByName(根据主机名称,返回一个IPHostEntry 对象: IPHostEntry GetHostByName(string hostName 其中IPHostEntry把一个DNS主机名与一个别名和IP地址的数组相关联,包含三个属性: AddressList:一个IPAddress对象的数组 Aliases:一个字符串对象数组 HostName:一个用于主机名的字符串对象3、GetHostByAddress(类似于GetHostByName(,只不过这里的参数是IP地址,而不是主机名,也返回一个IPHostEntry对象。IPHostEntry GetHostByAddress(IP

4、Address address IPHostEntry GetHostByAddress(string address 4、Resolve( 当我们不知道输入的远程主机的地址是哪种格式(主机名或IP地址)时,用以上二种方法来实现,我们可能还要通过判断客户输入的格式,才能正确使用,但dns类提供一更简单的方法Resolve(,该方法可以接受主机名格式或IP地址格式的任何一种地址,并返回IPHostEntry对象。-在上一篇中,列了一些常用的方法,可以说这些是一些辅助性的方法,对于分析网络中的主机属性非常有用。在这篇中,将会介绍一下面向连接(TCP)socket编程,其中辅以实例,代码可供下载。对

5、于TCP的Socket编程,主要分二部分:一、服务端Socket侦听:服务端Socket侦听主要分以下几个步骤,按照以下几个步骤我们可以很方便的建立起一个Socket侦听服务,来侦听尝试连接到该服务器的客户Socket,从而建立起连接进行相关通讯。1、创建IPEndPoint实例,用于Socket侦听时绑定1IPEndPointipep=newIPEndPoint(IPAddress.Any,6001;2、创建套接字实例1/创建一个套接字2serverSocket=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolTy

6、pe.Tcp;这里创建的时候用ProtocolType.Tcp,表示建立一个面向连接(TCP的Socket。3、将所创建的套接字与IPEndPoint绑定1/将所创建的套接字与IPEndPoint绑定2serverSocket.Bind(ipep;4、设置套接字为收听模式 1/设置套接字为收听模式2serverSocket.Listen(10;以上这四步,我们已经建立了Socket的侦听模式,下面我们就来设置怎么样来获取客户Socket连接的实例,以及连接后的信息发送。5、在套接字上接收接入的连接 1while(true23try45/在套接字上接收接入的连接6clientSocket=ser

7、verSocket.Accept(;7clientThread=newThread(newThreadStart(ReceiveData;8clientThread.Start(;910catch(Exceptionex1112MessageBox.Show(listeningError:+ex.Message;1314通过serverSocket.Accept(来接收客户Socket的连接请求,在这里用循环可以实现该线程实时侦听,而不是只侦听一次。当程序运行serverSocket.Accept(时,会等待,直到有客户端Socket发起连接请求时,获取该客户Socket,如上面的client

8、Socket。在这里我用多线程来实现与多个客户端Socket的连接和通信,一旦接收到一个连接后,就新建一个线程,执行ReceiveData功能来实现信息的发送和接收。6、在套接字上接收客户端发送的信息和发送信息1privatevoidReceiveData(23boolkeepalive=true;4Sockets=clientSocket;5Bytebuffer=newByte1024;67/根据收听到的客户端套接字向客户端发送信息8IPEndPointclientep=(IPEndPoints.RemoteEndPoint;9:+clientep.Address+(+clientep.Po

9、rt+;10stringwelcome=Welcometomytestsever;11bytedata=newbyte1024;1213s.Send(data,data.Length,SocketFlags.None;1415while(keepalive1617/在套接字上接收客户端发送的信息18intbufLen=0;19try2021bufLen=s.Available;2223s.Receive(buffer,0,bufLen,SocketFlags.None;24if(bufLen=025continue;2627catch(Exceptionex2829MessageBox.Sho

10、w(ReceiveError:+ex.Message;30return;3132clientep=(IPEndPoints.RemoteEndPoint;33string343536373839以上就是服务端Socket侦听模式的实现,只要有远程客户端Socket连接上后,就可以轻松的发送信息和接收信息了。下面我们来看看客户端Socket是怎么连接上服务器的。二、客户端连接客户端Socket连接相对来说比较简单了,另外说明一下,在执行客户端连接前,服务端Socket侦听必须先启动,不然会提示服务器拒绝连接的信息。1、创建IPEndPoint实例和套接字1/创建一个套接字2IPEndPointi

11、pep=new3clientSocket=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp;这个跟服务端Socket侦听差不多,下面一步由服务端Socket的侦听模式变成连接模式。2、将套接字连接到远程服务器1/将套接字与远程服务器地址相连2try34clientSocket.Connect(ipep;56catch(SocketExceptionex78MessageBox.Show(connecterror:+ex.Message;9return;10前面已说明,如果在执行Socket连接时,服务

12、器的Socket侦听没有开启的话,会产生一个SocketException异常,如果没有异常发生,那恭喜你,你已经与服务器连接上了,接下来就可以跟服务器通信了。3、接收信息1while(true23/接收服务器信息4intbufLen=0;5try67bufLen=clientSocket.Available;89clientSocket.Receive(data,0,bufLen,SocketFlags.None;10if(bufLen=01112continue;131415catch(Exceptionex1617MessageBox.Show(ReceiveError:+ex.Mess

13、age;18return;192021string222324254、发送信息1/向服务器发送信息23bytedata=newbyte1024;45clientSocket.Send(data,data.Length,SocketFlags.None;客户端的发送信息和接收信息跟服务器的接收发送是一样的,只不过一个是侦听模式而另一个是连接模式。以下是程序的运行界面,这些在源码下载里都可以看到:1、服务端界面:2、客户端界面:另外提一下,这里服务端开启侦听服务、客户端连接服务端都采用线程方式来实现,这样服务端能够跟多个客户端同时通信,不用等候,当然还有另外一种方式可以实现那就是异步socket。

14、源码下载:/Files/licongjie/SocketTest.rar -在上一篇中已经介绍了利用Socket建立服务端和客户端进行通信,如果需要的朋友可以访问Socket网络编程学习笔记(2):面向连接的Socket。在本篇中,将利用C套接字的助手类来简化Socket编程,使得刚刚接触网络编程的朋友更容易上手。跟上篇一样,通过C套接字的助手类来编程同样分服务端和客户端。一、服务端侦听模式1、创建套接字与IPEndPoint绑定,并设置为侦听模式。1/创建IPEndPoint实例2IPEndPointipep=newIPEndPoint(IPAddress.Any,6001;3/*/*4/创

15、建一个套接字5serverSocket=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp;6/将所创建的套接字与IPEndPoint绑定7serverSocket.Bind(ipep;8/设置套接字为收听模式9serverSocket.Listen(10;10*/11serverTcp=newTcpListener(ipep;12serverTcp.Start(;其中注释掉的部分是利用Socket来创建侦听,这里可以看到用套接字助手类只通过二行就可以建立起侦听,而且如果要更方便一些,可以不指定IPEn

16、dPoint,单指定端口就可以了,如: 1serverTcp=newTcpListener(6001;2serverTcp.Start(;2、侦听并获取接入的客户Socket连接1while(true23try45/在套接字上接收接入的连接6/clientSocket=serverSocket.Accept(;7clientTcp=serverTcp.AcceptTcpClient(;8clientThread=newThread(newThreadStart(ReceiveData;9clientThread.Start(;1011catch(Exceptionex1213MessageBo

17、x.Show(listeningError:+ex.Message;1415这里利用clientTcp = serverTcp.AcceptTcpClient(;来接收连接的TcpClient对象,我们可以通过 1clientSocket=serverTcp.AcceptSocket(;来接收一个Socket对象,如果接收的是一个Socket对象,那么接下来的接收和发送信息跟上篇一样,如果接收的是TcpClient对象,那么我们来看一下如何来接收和发送信息:3 、接收和发送信息1privatevoidReceiveData(23boolkeepalive=true;4TcpClients=cl

18、ientTcp;5NetworkStreamns=s.GetStream(;6Bytebuffer=newByte1024;78/根据收听到的客户端套接字向客户端发送信息910:+clientep.Address+(+clientep.Port+;11stringwelcome=Welcometomytestsever;12bytedata=newbyte1024;1314/s.Send(data,data.Length,SocketFlags.None;15ns.Write(data,0,data.Length;1617while(keepalive1819/在套接字上接收客户端发送的信息2

19、0intbufLen=0;21try2223bufLen=s.Available;24/s.Receive(buffer,0,bufLen,SocketFlags.None;25ns.Read(buffer,0,bufLen;26if(bufLen=027continue;2829catch(Exceptionex3031MessageBox.Show(ReceiveError:+ex.Message;32return;333435string363738394041通过NetworkStream ns = s.GetStream(;可以获取网络流对象,以此来发送和接收信息。二、客户端连接1、

20、创建套接字并连接到服务器1/创建一个套接字2IPEndPointipep=new3/clientSocket=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp;4clientTcp=newTcpClient(;56/将套接字与远程服务器地址相连7try89/clientSocket.Connect(ipep;10clientTcp.Connect(ipep;1112catch(SocketExceptionex1314MessageBox.Show(connecterror:+ex.Message;1

21、5return;162、接收服务器发送的信息1ns=clientTcp.GetStream(;2while(true34/接收服务器信息5intbufLen=0;6try78/bufLen=clientSocket.Available;9bufLen=clientTcp.Available;1011/clientSocket.Receive(data,0,bufLen,SocketFlags.None;12ns.Read(data,0,bufLen;13if(bufLen=01415continue;161718catch(Exceptionex1920MessageBox.Show(Rece

22、iveError:+ex.Message;21return;222324string25262728同服务端,通过ns = clientTcp.GetStream(;获取网络流来读取服务端发过来的信息。3、向服务端发送信息1/向服务器发送信息23bytedata=newbyte1024;45/clientSocket.Send(data,data.Length,SocketFlags.None;6ns.Write(data,0,data.Length;到这里,我们可以实现客户端与服务端的连接和通讯了。一些方法跟上一篇提到的类似,这里就不再详述。接下来,讲一下关于Socket发送的消息边界处理问

23、题、发送实体类数据问题以及利用线程池来改善线程创建和分配问题。源码下载:/Files/licongjie/SocketTest1.rar-在前面的几篇中,讲了关于套接字Socket以及利用套接字助手类来进行服务端和客户端之间的通信,在此中间并没有对发送的信息进行任何的处理。在本篇中将会讲一下TCP通信的信息边界问题。通过套接字或其助手类来接收信息时,是从缓存区里一次性把全部的缓存读取出来,只要你设置的缓存够大,这样就会导致这样的情况出现。如果服务端连续发送信息到客户端,如连续发送字符串“message 1”、“message 2”、“message 3”、“message 4”、“messag

24、e 5”,预想的是在客户端也是能够收完整的字符串,如果用前两篇中的方法,在同台机子上测试,是正常的。如果把客户端与服务端部署在不同的机器上,则会出现一些异想不到的现象。如“3message 4”,这个就是消息的边界问题,解决这个问题,方法有很多,现抽取其中几个来讲一下:1、固定尺寸的消息这是最简单也是最昂贵的解决TCP消息问题的方案。就是设计一种协议,永远以固定的长度传递消息,通过将所有的消息都设置为固定的尺寸,远程设备中接收到完整的消息时,TCP接收程序就能够了解发送的情况了。这意味着必须将短消息加长,造成网络带宽资源的浪费。2、使用消息尺寸信息这个方案允许使用可变长度的消息,惟一的不足就是

25、接收端的远程设置必须了解每一个变长消息的确切长度。具体的方法是,在发送消息的时候,一起发送该消息的长度。那么在客户端接收的时候就能知道该消息的长度是多少,再来读取消息。3、使用消息标记该方案使用预先确定的一个字符(或多个字符)来指定消息的结束,通过这种方式来分隔不同的消息。但用这种方法必须对所接收到的每一个字符进行检查以便确定为结束标记,这对于大型消息来说,可能导致系统性能的下降,不过对于C语言来说,提供了一些类,能够用于简化这个过程,那就是System.IO命名空间流类,下面我们也着重来讲一下这各个方法。至于第二种方法,将在下一篇中与在消息中传送实体类信息相结合来讲述。在上一篇中,我们已经提

26、到NetworkStream类,利用该类来传送和接收消息。在这里,再提一下另外的二个流类,那就是StreamReader和StreamWriter,这二个类也可用于TCP协议发送和接收文本消息。当我们得到Socket连接的一个NetworkStream对象时,可以通过下面的方法得到StreamWriter和StreamReader对象。1NetworkStreamns=s.GetStream(;2StreamReadersr=newStreamReader(ns;3StreamWritersw=newStreamWriter(ns;这样可以通过StreamWriter来发送消息,通过Strea

27、mReader来接收消息:1/发送消息2stringwelcome=Welcometomytestsever;34sw.WriteLine(welcome;5sw.Flush(;接收消息:1/接收消息2stringdata=;3data=sr.ReadLine(;这样是不是比以前的做法更简单了,而且同时也解决了TCP消息边界问题了。但是用这各方法必须得注意以下二点:1、这种方法其实就是利用消息标记来解决边界问题的,这里的标记就是换行符,也就是说,StreamWriter中的WriteLine(和StreamReader中的ReadLine(一定要成对使用,不然如果发送的信息中没有换行符,则客户

28、机中用ReadLine(读取信息时,将无法结束,将堵塞程序的执行,一直等待换行符。2、另外还要保证在发送的消息本身不应该带有换行符,如果消息本身带有换行符,则这些换行符将被ReadLine(方法错误地作为标记,影响数据的完整性。关于TCP消息边界处理就暂时讲到这里。在下一篇中,将讲述传送实体类方面的问题。Socket网络编程学习笔记(5):发送和接收实体类数据 在前面讲述的篇幅中,发送的都是文本信息,我们只要通过Encoding中的几个方法把文本转化成二进制数组就可以利用Socket来传输了,这对于一些基本的信息传输能够得到满足,但对于一些复杂的消息交流,则有些“吃力”。我们有时候会把一些信息

29、封闭在一个类中,如果Socket能够传送类对象,那么一些复杂的问题能够通过面向对象来解决了,即方便又安全。大家都知道,要想在网络上传输信息,必须要经过序列化才行,所以在传送类对象时,首选必须对该类对象进行序列化,才能够在网络上进行传输。序列化类对象有三种序列化方法:1、Xml序列化2、Binary序列化3、Soap序列化这几种序列化方法,运用方法相类似,只不过用到的类不一样。在这里也不一一讲述了,有兴趣的朋友可以到网上搜一搜,相信会有不少的收获。这里主要讲一下利用Soap序列化来传送消息。1、首先我们先来建立一个实体类,用来做消息的载体类对象1usingSystem;2using3usingS

30、ystem.Text;45namespacesbwConsole67Serializable8publicclassSocketData910privateOperateType_operateType;11privateOperateInfo_operateInfo;12privatestring_connString;13privatestring_clientIP;14privatestring_serverIP;1516/*/17/指令传输数据18/ 19 / 指令类型 20 / 指令信息 21 / ASP 数据库连接字符串 22 / 子服务器 IP 23 / ASP 服务器 IP 2

31、4 public SocketData(OperateTypeoperateType,OperateInfooperateInfo, 25 string connString, string clientIP, string serverIP 26 27 _operateType=operateType; 28 _operateInfo=operateInfo; 29 _connString=connString; 30 _clientIP=clientIP; 31 _serverIP=serverIP; 32 33 34 /*/ / 35/指令类型36/ 37 public OperateT

32、ypeOperateType 38 39 get return _operateType; 40 set _operateType=value; 41 42 /*/ / 43/指令信息44/ 45 public OperateInfoOperateInfo 46 47 get return _operateInfo; 48 set _operateInfo=value; 49 50 /*/ / 51/ASP数据库连接字符串52/ 53 public string ConnString 54 55 get return _connString; 56 set _connString=value;

33、 57 58 /*/ / 59/子服务器IP60/ 61 public string ClientIP 62 63 get return _clientIP; 64 set _clientIP=value; 65 66 /*/ / 67/ASP服务器IP68/ 69 public string ServerIP 70 71 get return _serverIP; 72 set _serverIP=value; 73 74 75 76 /*/ / 77/指令类型78/ 79 public enum OperateType 80 81 /*/ / 82/网站操作83/ 84 Web=0, 85

34、 /*/ / 86/升级87/ 88 Upgrade, 89 /*/ / 90/迁移91/ 92 Transfer 93 94 95 /*/ / 96/指令信息97/ 98 public enum OperateInfo 99 100 /*/ / 101/发送102/ 103 Send=0, 104 /*/ / 105/出错106/ 107 Error, 108 /*/ / 109/成功110/ 111 Success, 112 /*/ / 113/重发114/ 115 SendAgain 116 117 118 2、发送前先把类对象进行Soap序列化消息发送方法1publicstaticvoidSend(NetworkStreamns,SocketDatasd23IFormatterformatter=newSoapFormatter(;4MemoryStreammem=newMemoryStream(;56formatter.Serialize(mem,sd;7bytedata=mem.GetBuffer(;8intmemsize=(intmem.Length;9bytesize=BitConver

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论