C# Socket网络编程精华篇

http://www.cnblogs.com/weilengdeyu/archive/2013/03/08/2949101.html

我们在讲解Socket编程前,先看几个和Socket编程紧密相关的概念:

  1. TCP/IP层次模型

    当然这里我们只讨论重要的四层

       01,应用层(Application):应用层是个很广泛的概念,有一些基本相同的系统级TCP/IP应用以及应用协议,也有许多的企业应用和互联网应用。http协议在应用层运行。

       02,传输层(Tanspot):传输层包括UDP和TCP,UDP几乎不对报文进行检查,而TCP

提供传输保证。

      03,网络层(Netwok):网络层协议由一系列协议组成,包括ICMP、IGMP、RIP、OSPF、IP(v4,v6)等。

      04,链路层(Link):又称为物理数据网络接口层,负责报文传输。

   然后我们来看下tcp层次模型图

 C# Socket网络编程精华篇

     从上图中可以看出,应用程序在应用层运行,在传输层,在数据前加上了TCP头,在

网络层加上的IP头,在数据链路层加上了帧。

   2,端口

    端口号范围:0-65535,总共能表示65536个数。

   按端口号可分为3大类

  (1)公认端口(WellKnownPorts):从0到1023,它们紧密绑定(binding)于一些服务。通常这些端口的通讯明确表明了某种服务的协议。例如:80端口实际上总是HTTP通讯。

  (2)注册端口(RegisteredPorts):从1024到49151。它们松散地绑定于一些服务。也就是说有许多服务绑定于这些端口,这些端口同样用于许多其它目的。例如:许多系统处理动态端口从1024左右开始。

  (3)动态和/或私有端口(Dynamicand/orPrivatePorts):从49152到65535。理论上,不应为服务分配这些端口。实际上,机器通常从1024起分配动态端口。

3.TCP和UDP报文

  下面一起来看下TCP和UDP的报文图

 C# Socket网络编程精华篇

      从图中我们可以看出TCP和UDP中都有校验和,但是在UDP报文中,一般不使用校验和,这样可以加快数据传输的速度,但是数据的准确性可能会受到影响。换句话说,Tcp协议都有校验和,为了保证传输数据的准确性。

3.Socket

     Socket包括Ip地址和端口号两部分,程序通过Socket来通信,Socket相当于操作系统的一个组件。Socket作为进程之间通信机制,通常也称作”套接字”,用于描述IP地址和端口号,是一个通信链的句柄。说白了,就是两个程序通信用的。

生活案例对比:

      Socket之间的通信可以类比生活中打电话的案例。任何用户在通话之前,首先要占有一部电话机,相当于申请一个Socket,同时要知道对方的号码,相当于对方有一个固定的Socket,然后向对方拨号呼叫,相当于发出连接请求。假如对方在场并空闲,拿起 电话话筒,双方就可以进行通话了。双方的通话过程,是一方向电话机发出信号和对方从电话机接收信号的过程,相当于向socket发送数据和从socket接收数据。通话结束后,一方挂起电话机,相当于关闭socket,撤销连接。

     注意:Socket不仅可以在两台电脑之间通信,还可以在同一台电脑上的两个程序间通信。

4,端口进阶(深入)

    通过IP地址确定了网络中的一台电脑后,该电脑上可能提供很多提供服务的应用,每一个应用都对应一个端口。

在Internet上有很多这样的主机,这些主机一般运行了多个服务软件 ,同时提供几种服务,每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务(应用程序)

    例如:http 使用80端口,   ftp使用21端口     smtp使用25端口

5.Socket分类

     Socket主要有两种类型:

  1. 流式Socket

          是一种面向连接的Socket,针对于面向连接的TCP服务应用,安全,但是效率低

     2,数据报式Socket

          是一种无连接的Socket,对应于无连接的UDP服务应用,不安全,但效率高

 6. Socket一般应用模式(服务器端和客户端)

     服务器端的Socket(至少需要两个)

        01.一个负责接收客户端连接请求(但不负责与客户端通信)

       02.每成功接收到客户端的连接便在服务器端产生一个对应的复杂通信的Socket

          021.在接收到客户端连接时创建

         022. 为每个连接成功的客户端请求在服务器端都创建一个对应的Socket(负责和客户端通信)

    客户端的Socket

  1. 必须指定要连接的服务器地址和端口
  2. 通过创建一个Socket对象来初始化一个到服务器端的TCP连接

 C# Socket网络编程精华篇

      通过上图,我们可以看出,首先服务器会创建一个负责监听的socket,然后客户端通过socket连接到服务器指定端口,最后服务器端负责监听的socket,监听到客户端有连接过来了,就创建一个负责和客户端通信的socket。

下面我们来看下Socket更具体的通信过程:

Socket的通讯过程

  服务器端:

    01,申请一个socket

    02,绑定到一个IP地址和一个端口上

    03,开启侦听,等待接收连接

  客户端:

    01,申请一个socket

   02,连接服务器(指明IP地址和端口号)

   服务器端接收到连接请求后,产生一个新的socket(端口大于1024)与客户端建立连接并进行通信,原监听socket继续监听。

  注意:负责通信的Socket不能无限创建,创建的数量和操作系统有关。

 7.Socket的构造函数

    Public Socket(AddressFamily addressFamily,SocketType  socketType,ProtocolType  protocolTYpe)

    AddressFamily:指定Socket用来解析地址的寻址方案。例如:InterNetWork指示当Socket使用一个IP版本4地址连接

   SocketType:定义要打开的Socket的类型

   Socket类使用ProtocolType枚举向Windows  Sockets  API通知所请求的协议

注意:

   1,端口号必须在 1 和 65535之间,最好在1024以后。

   2,要连接的远程主机必须正在监听指定端口,也就是说你无法随意连接远程主机。

如:

IPAddress addr = IPAddress.Parse("127.0.0.1");

IPEndPoint endp = new IPEndPoint(addr,,9000);

         服务端先绑定:serverWelcomeSocket.Bind(endp)

         客户端再连接:clientSocket.Connect(endp)

   3,一个Socket一次只能连接一台主机

   4,Socket关闭后无法再次使用

  5,每个Socket对象只能与一台远程主机连接。如果你想连接到多台远程主机,你必须创建多个Socket对象。

8.Socket常用类和方法

  相关类:

   IPAddress:包含了一个IP地址

   IPEndPoint:包含了一对IP地址和端口号

 方法:

   Socket():创建一个Socket

   Bind():绑定一个本地的IP和端口号(IPEndPoint)

   Listen():让Socket侦听传入的连接吃那个病,并指定侦听队列容量

   Connect():初始化与另一个Socket的连接

   Accept():接收连接并返回一个新的Socket

   Send():输出数据到Socket

   Receive():从Socket中读取数据

   Close():关闭Socket,销毁连接

  接下来,我们同一个简单的服务器和客户端通信的案例,来看下Sokcet的具体用法,效果图如下:

 C# Socket网络编程精华篇
C# Socket网络编程精华篇

关键代码:

服务器端代码:

复制代码
  1 private void Form1_Load(object sender, EventArgs e)

  2 

  3         {

  4 

  5             Control.CheckForIllegalCrossThreadCalls = false;

  6 

  7         }

  8 

  9  

 10 

 11         private void btnListen_Click(object sender, EventArgs e)

 12 

 13         {

 14 

 15             //ip地址

 16 

 17             IPAddress ip = IPAddress.Parse(txtIP.Text);

 18 

 19            // IPAddress ip = IPAddress.Any;

 20 

 21             //端口号

 22 

 23             IPEndPoint point=new IPEndPoint(ip,int.Parse(txtPort.Text));

 24 

 25             //创建监听用的Socket

 26 

 27             /*

 28 

 29              * AddressFamily.InterNetWork:使用 IP4地址。

 30 

 31 SocketType.Stream:支持可靠、双向、基于连接的字节流,而不重复数据。此类型的 Socket 与单个对方主机进行通信,并且在通信开始之前需要远程主机连接。Stream 使用传输控制协议 (Tcp) ProtocolType 和 InterNetworkAddressFamily。

 32 

 33 ProtocolType.Tcp:使用传输控制协议。

 34 

 35              */

 36 

 37             //使用IPv4地址,流式socket方式,tcp协议传递数据

 38 

 39             Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);

 40 

 41             //创建好socket后,必须告诉socket绑定的IP地址和端口号。

 42 

 43             //让socket监听point

 44 

 45             try

 46 

 47             {

 48 

 49                 //socket监听哪个端口

 50 

 51                 socket.Bind(point);

 52 

 53                 //同一个时间点过来10个客户端,排队

 54 

 55                 socket.Listen(10);

 56 

 57                 ShowMsg("服务器开始监听");

 58 

 59                 Thread thread = new Thread(AcceptInfo);

 60 

 61                 thread.IsBackground = true;

 62 

 63                 thread.Start(socket);

 64 

 65             }

 66 

 67             catch (Exception ex)

 68 

 69             {

 70 

 71                

 72 

 73                ShowMsg(ex.Message);

 74 

 75             }

 76 

 77         }

 78 

 79         //记录通信用的Socket

 80 

 81         Dictionary<string,Socket> dic=new Dictionary<string, Socket>();

 82 

 83        // private Socket client;

 84 

 85         void AcceptInfo(object o)

 86 

 87         {

 88 

 89             Socket socket = o as Socket;

 90 

 91             while (true)

 92 

 93             {

 94 

 95                 //通信用socket

 96 

 97                 try

 98 

 99                 {

100 

101                     //创建通信用的Socket

102 

103                   Socket  tSocket = socket.Accept();

104 

105                   string point = tSocket.RemoteEndPoint.ToString();

106 

107                     //IPEndPoint endPoint = (IPEndPoint)client.RemoteEndPoint;

108 

109                     //string me = Dns.GetHostName();//得到本机名称

110 

111                     //MessageBox.Show(me);

112 

113                  ShowMsg(point + "连接成功!");

114 

115                  cboIpPort.Items.Add(point);

116 

117                  dic.Add(point, tSocket);

118 

119                     //接收消息

120 

121                     Thread th = new Thread(ReceiveMsg);

122 

123                     th.IsBackground = true;

124 

125                     th.Start(tSocket);

126 

127                 }

128 

129                 catch (Exception ex)

130 

131                 {

132 

133                     ShowMsg(ex.Message);

134 

135                     break;

136 

137                 }

138 

139             }

140 

141         }

142 

143         //接收消息

144 

145         void ReceiveMsg(object o)

146 

147         {

148 

149             Socket client = o as Socket;

150 

151             while (true)

152 

153             {

154 

155                 //接收客户端发送过来的数据

156 

157                 try

158 

159                 {

160 

161                     //定义byte数组存放从客户端接收过来的数据

162 

163                     byte[] buffer = new byte[1024 * 1024];

164 

165                     //将接收过来的数据放到buffer中,并返回实际接受数据的长度

166 

167                     int n = client.Receive(buffer);

168 

169                     //将字节转换成字符串

170 

171                     string words = Encoding.UTF8.GetString(buffer, 0, n);

172 

173                   

174 

175                     ShowMsg(client.RemoteEndPoint.ToString() + ":" + words);

176 

177                 }

178 

179                 catch (Exception ex)

180 

181                 {

182 

183                    ShowMsg(ex.Message);

184 

185                     break;

186 

187                 }

188 

189             }

190 

191         }

192 

193  

194 

195         void ShowMsg(string msg)

196 

197         {

198 

199             txtLog.AppendText(msg+"\r\n");

200 

201         }

202 

203  

204 

205         private void Form1_FormClosing(object sender, FormClosingEventArgs e)

206 

207         {

208 

209             //主窗体关闭时关闭子线程

210 

211           

212 

213         }

214 

215         //给客户端发送消息

216 

217         private void btnSend_Click(object sender, EventArgs e)

218 

219         {

220 

221             try

222 

223             {

224 

225                 ShowMsg(txtMsg.Text);

226 

227                 string ip = cboIpPort.Text;

228 

229                 byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text);

230 

231                 dic[ip].Send(buffer);

232 

233                 // client.Send(buffer);

234 

235             }

236 

237             catch (Exception ex)

238 

239             {

240 

241                ShowMsg(ex.Message);

242 

243             }

244 

245  

246 

247         }
复制代码

 

客户端代码:

复制代码
  1 Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

  2 

  3         private void btnConnection_Click(object sender, EventArgs e)

  4 

  5         {

  6 

  7             //连接到的目标IP

  8 

  9             IPAddress ip = IPAddress.Parse(txtIP.Text);

 10 

 11             //IPAddress ip = IPAddress.Any;

 12 

 13             //连接到目标IP的哪个应用(端口号!)

 14 

 15             IPEndPoint point=new IPEndPoint(ip,int.Parse(txtPort.Text));

 16 

 17             try

 18 

 19             {

 20 

 21                 //连接到服务器

 22 

 23                 client.Connect(point);

 24 

 25                 ShowMsg("连接成功");

 26 

 27                 ShowMsg("服务器" + client.RemoteEndPoint.ToString());

 28 

 29                 ShowMsg("客户端:" + client.LocalEndPoint.ToString());

 30 

 31                 //连接成功后,就可以接收服务器发送的信息了

 32 

 33                 Thread th=new Thread(ReceiveMsg);

 34 

 35                 th.IsBackground = true;

 36 

 37                 th.Start();

 38 

 39             }

 40 

 41             catch (Exception ex)

 42 

 43             {

 44 

 45                 ShowMsg(ex.Message);

 46 

 47             }

 48 

 49         }

 50 

 51         //接收服务器的消息

 52 

 53         void ReceiveMsg()

 54 

 55         {

 56 

 57             while (true)

 58 

 59             {

 60 

 61                 try

 62 

 63                 {

 64 

 65                     byte[] buffer = new byte[1024 * 1024];

 66 

 67                     int n = client.Receive(buffer);

 68 

 69                     string s = Encoding.UTF8.GetString(buffer, 0, n);

 70 

 71                     ShowMsg(client.RemoteEndPoint.ToString() + ":" + s);

 72 

 73                 }

 74 

 75                 catch (Exception ex)

 76 

 77                 {

 78 

 79                     ShowMsg(ex.Message);

 80 

 81                     break;

 82 

 83                 }

 84 

 85             }

 86 

 87           

 88 

 89         }

 90 

 91  

 92 

 93         void ShowMsg(string msg)

 94 

 95         {

 96 

 97             txtInfo.AppendText(msg+"\r\n");

 98 

 99         }

100 

101  

102 

103         private void btnSend_Click(object sender, EventArgs e)

104 

105         {

106 

107             //客户端给服务器发消息

108 

109             if (client!=null)

110 

111             {

112 

113                 try

114 

115                 {

116 

117                    ShowMsg(txtMsg.Text);

118 

119                     byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text);

120 

121                     client.Send(buffer);

122 

123                 }

124 

125                 catch (Exception ex)

126 

127                 {

128 

129                    ShowMsg(ex.Message);

130 

131                 }

132 

133             }

134 

135            

136 

137         }

138 

139  

140 

141         private void ClientForm_Load(object sender, EventArgs e)

142 

143         {

144 

145             Control.CheckForIllegalCrossThreadCalls = false;

146 

147         }
复制代码

       好了,到这里我们对Socket的讨论就告一个段落了。希望以后还有时间来研究这方面的知识。因为我深深的知道,能和大家探讨也是一种幸福。

 2013年3月7日0:00点

你可能感兴趣的:(socket)