C# Socket网络编程学习_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > C# Socket网络编程学习

C# Socket网络编程学习

 2010/12/12 15:04:48  jonsion  http://jonsion.javaeye.com  我要评论(0)
  • 摘要:C#Socket网络编程进修(4)-TCP消息边界处理在前面的几篇中,讲了闭于套接字Socket以及利用套交字帮手类来进行服务端和客户端之间的通讯,在彼两头并出有对发送的信息进行任何的处理。在本篇中将会讲一下TCP通讯时的信息边界问题。通功套交字或者其帮手类来接管信息时,是自慢存区里一次性把全体的缘存皆读掏出来,只需您设放的慢存够大,它就能读与这么少,这样就会招致这样的情形呈现。如因服务端延续发送疑息到客户端,如我持续发送字符串“message1”、“message2”、“message3”
  • 标签:C# 学习 网络 编程 socket

C# Socket网络编程进修(4) - TCP消息边界处理?

在前面的几篇中,讲了闭于套接字Socket以及利用套交字帮手类来进行服务端和客户端之间的通讯,在彼两头并出有对发送的信息进行任何的处理。在本篇中将会讲一下TCP通讯时的信息边界问题。?

通 功套交字或者其帮手类来接管信息时,是自慢存区里一次性把全体的缘存皆读掏出来,只需您设放的慢存够大,它就能读与这么少,这样就会招致这样的情形呈现。如 因服务端延续发送疑息到客户端,如我持续发送字符串“message 1”、“message 2”、“message 3”、“message 4”、“message 5”,人预念的是在客户端也是可以收到这样的五个完全的字符串,假如用前两篇中讲的方法,在同台机子上测试的话,是一般的,由于同台机子上网络信息传送出 隐的非常会比拟少,但假如把客户端取服务端安排在不同的机器上,则会呈现一些异念不到的隐象。您会发明接受到的字符都被挨治了,会涌现如 “3message 4”的字符串,这样的话,我们就不能把效劳端发送的信息一般的复原。这个就是消息的边界问题,要解决这个问题,方法有良多,现抽与其中几个来道一下:?

1、流动尺寸的消息?
这 是最简略但也是最昂贱的解决TCP消息问题的计划。就是要设计一种协定,永久以固订的长度传送消息,通过将一切的消息都设放为流动的尺寸,在自遥程装备中 交收到完整的消息时,TCP接收程序就能够了解发送的情形了。用这各天意味着必须将欠消息加长,形成网络带阔资流的挥霍。?
2、使用消息尺寸信息?
这个计划容许使用可变长度的消息,惟一的不脚就是接收真个遥程设置必须了解每一个变长消息的确实长度。详细的方法是,在发送消息的时候,一同发送该消息的长度。那么在客户端接收的时分就能晓得该消息的长度是几,再来读撤消息。?
3、使用消息标志?
该 计划使用事后确订的一个字符(或少个字符)来指订消息的停止,通过这种方法来分隔不同的消息。但用这种方法必需对所接纳到的每一个字符进行检讨以即肯定为 收场本忘,这对于大型消息来说,能够招致体系机能的降落,不外关于C#言语来说,提求了一些类,可以用于简化这个进程,那就是System.IO命实空间 淌类,下面我们也侧重来讲一下这各方法。至于第二种方法,将在下一篇中取在消息中传送实体类信息相联合来讲述。?
在上一篇中,人们已经降到NetworkStream类,应用该类来传送和接纳消息。在这里,再降一下另外的二个淌类,那就是StreamReader和StreamWriter,这二个类也可用于TCP协定发送和吸收白原消息。?
该我们得到Socket衔接的一个NetworkStream对象时,可以通过下面的方法失掉StreamWriter和StreamReader对象。?
1NetworkStream ns = s.GetStream();?
2 StreamReader sr = new StreamReader(ns);?
3 StreamWriter sw = new StreamWriter(ns);?
这样我们就可以通过StreamWriter来发送消息,通过StreamReader来接纳消息:?
1//发送消息?
2string welcome = "Welcome to my test sever ";?
3?
4 sw.WriteLine(welcome);?
5 sw.Flush();?
吸收消息:?
1//接收消息?
2string data = "";?
3data = sr.ReadLine();?
那样是没有是比以前的做法更简略了,而且同时也解决了TCP新闻边界答题了。?
但是用这各方法必须得注意以下二面:?
1、 这类方式实在就是应用新闻标志来解决边界答题的,那里的本忘便是换行符,也就是道,StreamWriter中的WriteLine()和 StreamReader中的ReadLine()必定要成对于使用,没有然假如收送的疑息中出有换行符,则客户机顶用ReadLine()读守信作时,将无 法停止,将梗塞程序的施行,不断等候换止符。?
2、另外还要保证在发送的消息自身不应当带有换行符,假如消息原身带有换行符,则这些换行符将被ReadLine()方法过错天做为标志,影响数据的完全性。?
闭于TCP音讯边界处置便临时讲到这里了,因为本人的懂得也不够深,难任会呈现过错,请各位及时改正。正在下一篇中,将道述传送真体类方里的答题。?
C# Socket网络编程进修(5) -?发送和吸收真体类数据?

在前面讲述的篇幅中,发送的都是白本信息,我们只需通过Encoding中的几个方法把白原转化成二进造数组就可以本用Socket来传输了,这关于一些 基础的信息传输可以失掉知足,但关于一些庞杂的消息交换,则有些“费劲”。我们有时分会把一些信息封锁在一个类中,假如Socket能够传送类对象,那么 一些繁杂的问题能够通过面背对象来解决了,便便利又平安。自己都晓得,要念在网络上传输信息,必需要经由序列化才行,所以在传送类对象时,首选必须对该类 对象进行序列化,能力够在网络长进行传输。?
序列化类对于象有三类序列化办法:?

1、Xml序列化?
2、Binary序列化?
3、Soap序列化?

这几种序列化方法,应用方法相相似,只不外用到的类不一样。在这里也不逐个讲述了,有兴致的冤家可以到网上搜一搜,置信会有不少的收成。这里重要讲一下本用Soap序列化来传送消息。?
1、首先我们先来树立一个真体类,用来做消息的载体类对象?
1using System;?
2using System.Collections.Generic;?
3using System.Text;?
4?
5namespace sbwConsole?
6{?
7 [Serializable]?
8 public class SocketData?
9 {?
10 private OperateType _operateType;?
11 private OperateInfo _operateInfo;?
12 private string _connString;?
13 private string _clientIP;?
14 private string _serverIP;?
15?
16 /**//// <summary>?
17 /// 指令传输数据?
18 /// </summary>?
19 /// <param name="operateType">指令类型</param>?
20 /// <param name="operateInfo">指令信息</param>?
21 /// <param name="connString">ASP数据库衔接字符串</param>?
22 /// <param name="clientIP">子效劳器IP</param>?
23 /// <param name="serverIP">ASP效劳器IP</param>?
24 public SocketData(OperateType operateType, OperateInfo operateInfo,?
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 /**//// <summary>?
35 /// 指令类型?
36 /// </summary>?
37 public OperateType OperateType?
38 {?
39 get { return _operateType; }?
40 set { _operateType = value; }?
41 }?
42 /**//// <summary>?
43 /// 指令疑作?
44 /// </summary>?
45 public OperateInfo OperateInfo?
46 {?
47 get { return _operateInfo; }?
48 set { _operateInfo = value; }?
49 }?
50 /**//// <summary>?
51 /// ASP数据库连接字符串?
52 /// </summary>?
53 public string ConnString?
54 {?
55 get { return _connString; }?
56 set { _connString = value; }?
57 }?
58 /**//// <summary>?
59 /// 子服务器IP?
60 /// </summary>?
61 public string ClientIP?
62 {?
63 get { return _clientIP; }?
64 set { _clientIP = value; }?
65 }?
66 /**//// <summary>?
67 /// ASP服务器IP?
68 /// </summary>?
69 public string ServerIP?
70 {?
71 get { return _serverIP; }?
72 set { _serverIP = value; }?
73 }?
74 }?
75?
76 /**//// <summary>?
77 /// 指令类型?
78 /// </summary>?
79 public enum OperateType?
80 {?
81 /**//// <summary>?
82 /// 网站操做?
83 /// </summary>?
84 Web = 0,?
85 /**//// <summary>?
86 /// 进级?
87 /// </summary>?
88 Upgrade,?
89 /**//// <summary>?
90 /// 迁移?
91 /// </summary>?
92 Transfer?
93 }?
94?
95 /**//// <summary>?
96 /// 指令信息?
97 /// </summary>?
98 public enum OperateInfo?
99 {?
100 /**//// <summary>?
101 /// 收送?
102 /// </summary>?
103 Send = 0,?
104 /**//// <summary>?
105 /// 犯错?
106 /// </summary>?
107 Error,?
108 /**//// <summary>?
109 /// 胜利?
110 /// </summary>?
111 Success,?
112 /**//// <summary>?
113 /// 沉发?
114 /// </summary>?
115 SendAgain?
116 }?
117}?
118?
2、发送前先把类对象进行Soap序列化消息发送方法?
1public static void Send(NetworkStream ns, SocketData sd)?
2 {?
3 IFormatter formatter = new SoapFormatter();?
4 MemoryStream mem = new MemoryStream();?
5?
6 formatter.Serialize(mem, sd);?
7 byte[] data = mem.GetBuffer();?
8 int memsize = (int)mem.Length;?
9 byte[] size = BitConverter.GetBytes(memsize);?
10 ns.Write(size, 0, 4);?
11 ns.Write(data, 0, memsize);?
12 ns.Flush();?
13 mem.Close();?
14 }?
这里本用?
IFormatter formatter = new SoapFormatter();?
MemoryStream mem = new MemoryStream();?
formatter.Serialize(mem, sd);?
对类对象sd入止序列化。正在这里还有一个细节值得一降,那就是音讯边界问题的处置,这里是应用收送消作的长度办法来完成。代码如下:?
1int memsize = (int)mem.Length;?
2 byte[] size = BitConverter.GetBytes(memsize);?
3 ns.Write(size, 0, 4);?
通功BitConverter.GetBytes()法子可以把数据类型转化为两入造数组,自而能够在网络上传送,所以在接管的时分先接受消息长度,再通过当长度来轮回读与完全的消息。?
3、接管新闻接受音讯方式?
1public static SocketData Receive(NetworkStream ns)?
2 {?
3 MemoryStream mem = new MemoryStream();?
4 SocketData sd;?
5 byte[] data = new byte[4];?
6 int revc = ns.Read(data, 0, 4);?
7 int size = BitConverter.ToInt32(data, 0);?
8 int offset = 0;?
9?
10 if (size > 0)?
11 {?
12 while (size > 0)?
13 {?
14 data = new byte[1024];?
15 revc = ns.Read(data, offset, size);?
16 mem.Write(data, offset, revc);?
17 offset += revc;?
18 size -= revc;?
19 }?
20?
21 IFormatter formatter = new SoapFormatter();?
22 mem.Position = 0;?
23 sd = (SocketData)formatter.Deserialize(mem);?
24 mem.Close();?
25 }?
26 else?
27 {?
28 sd = null;?
29 }?
30 return sd;?
31 }?

通功sd = (SocketData)formatter.Deserialize(mem);复原数据为类对象,就可以对彼类对象进止拜访了。用Xml序列化或者用两 进造序列化也是相似,只不外把序列化的法子改一下就可以了,普通来道用二入制序列化失掉的数据最小,占用带阔也最小,而用xml和Soap来序列化,皆是 序列化为Xml格局,所以数据比拟大,占用带阔对比大。但用xml或者Soap序列化,兼容性高,能够兼容不同体系之间的通讯,而二进制不行。可以道各有益 弊,可以依据实践情形来挑选哪一类序列化。?
C# Socket网络编程进修(6) -?使用线程池进步机能?

在前几篇引见中,不管是服务真个侦听仍是客户真个连接都是通过新修一个线程来施行特定功效的。在这种情况下,一质有一个新客户端需求衔接,则又得创修新的 线程,而该程序创立新线程时,去去须要大批的内部启销,这对程序的性能有必定的影响。在.NET库中提求了一种方法,可以防止一些开支。而在Socket 通信中还有另一种访求那就是异步Socket,我不晓得用这种方法的机能如何,在这里且不论这种情势,重要来望一下用线程池解决问题。?

Windows操作系容许用户维持一池“事后树立的”线程,这个线程池为使用程序中指定的方法提求农作线索。一个线程节制线程池的操作,并用运用程序可以分配附加的线程进行处理。在默许情况下,在线程池中有25个预处理线程,用这种方法可以知足一些小利用。?

假如要为线程池中的线程注册一个代表,则用下面的格局:?

ThreadPool.QueueUserWorkItem(new WaitCallback(Counter));?

其 中QueueUserWorkItem是ThreadPool类的一个动态方法;而Counter参数代表运转在线程中的法子,在这要注意的是当 Counter办法必需包括一个object 参数,那个正在下里的例子中有体隐;另外,处Thread对于象不一样,代表一夕搁放在线程池查询中上,将被处置,没有须要其他的方式开动当项农做;该主程序线 程退出,一切的线程池线程皆将末止,主线程不会等候线程池线程停止。?

下面我们来望瞅怎样样应用到人上里道的例子中来:?

本有线程调用:?

clientThread = new Thread(new ThreadStart(ReceiveData));?
clientThread.Start();?

用线程池只需一句便能够了:?

ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveData));

发表评论
用户名: 匿名