您的位置:首页 > 移动开发 > 微信开发

一个有用的Windows服务小程序——用来完成Server端的Socket通信

2007-10-13 08:35 399 查看
今天被迫要做一个接收通信的模块,以前从来都没有做过关于通信方面的东西,就像没有做过有关GIS方面的程序一样是头一次开发此类程序。
这个Socket通信说是自己的其实完全不是(如果哪位高人见到此程序是您本人开发的千万不要介意,本人也是在网上搜索出的,这个程序真的很不错,值得推广哦!在此谢谢发布此Socket通信程序的高人)。
此程序的大部分源码没有任何改动,只是原来的Server端是用C/S程序写的,为了能使Socket通信的Server端更灵活,在此将其改成一个Windows服务,因此也需要改动了一些Server端的代码和工程,但是基础类和Client端都没有改变。
对于我本人来说,Windows服务和Socket通信本人都不是很了解,只是经过了昨天简单的学习和研究才完成了此Windows服务Server端Socket通信程序,所以也说不出太多的门道,如果有清楚这方面知识的博友还希望能多多交流。好了,废话少说,开始正题了。
现在开始我们来讲解,如何一步一步地完成Windows服务Server端Socket通信程序。
我个人认为Windows服务只是包裹在Socket通信程序外的“一件外套”,所以核心还是我在网上找到的这个Socket程序,为此我们的第一步应该先开发出此Socket程序的类库。
1、打开Visual Studio.Net2003,单击菜单中的“文件”——>“新建”——>“项目”,在弹出的对话框左侧选择“Visual C#项目”,在右侧选择“类库”,下方的名称中输入“SocketLibrary”,位置自己随便选择一个路径。
2、删除自动创建的Class1.cs,新建如下的类名文件“Client.cs”、“Connection.cs”、“ConnectionCollection.cs”、“Message.cs”、“MessageCollection.cs”、“Server.cs”、“SocketBase.cs”和“SocketFactory.cs”。
3、各个类文件的代码如下:
(1)、Client.cs文件中的代码:




Client.cs文件代码


using System;


using System.Net;


using System.Net.Sockets;




namespace SocketLibrary






{




public class Client:SocketBase






{


public const int CONNECTTIMEOUT = 10;


public Client()






{




}




public Connection StartClient(IPAddress ipaddress,int port)

{


TcpClient client = new TcpClient();


client.SendTimeout = CONNECTTIMEOUT;


client.ReceiveTimeout = CONNECTTIMEOUT;




client.Connect(ipaddress,port);




this._connections.Add(new Connection(client.GetStream()));


this.StartListenAndSend();


return new Connection(client.GetStream());


}




public void StopClient()

{






this.EndListenAndSend();


}


}


}(2)、Connection.cs文件中的代码:




Connection.cs文件代码


using System;


using System.Net;


using System.Net.Sockets;




namespace SocketLibrary






{




/**//// <summary>


/// Connection 的摘要说明。


/// </summary>


public class Connection






{




public NetworkStream NetworkStream

{




get

{return _networkStream;}




set

{_networkStream = value;}


}


private NetworkStream _networkStream;




public string ConnectionName

{




get

{return _connectionName;}




set

{_connectionName = value;}


}


private string _connectionName;


public Connection(NetworkStream networkStream,string connectionName)






{


this._networkStream = networkStream;


this._connectionName = connectionName;


}




public Connection(NetworkStream networkStream):this(networkStream,string.Empty)

{


}


}


}(3)、ConnectionCollection.cs文件中的代码:




ConnectionCollection.cs文件代码


using System;






namespace SocketLibrary

{




public class ConnectionCollection:System.Collections.CollectionBase

{




public ConnectionCollection()

{




}




public void Add(Connection value)

{


List.Add(value);


}




public Connection this[int index]

{




get

{


return List[index] as Connection;


}




set

{


List[index] = value;


}


}




public Connection this[string connectionName]

{




get

{




foreach(Connection connection in List)

{


if(connection.ConnectionName == connectionName)


return connection;


}


return null;


}


}


}


}(4)、Message.cs文件中的代码:




Message.cs文件代码


using System;




namespace SocketLibrary






{


public class Message






{




public enum CommandHeader:byte

{


SendMessage = 1


}


public Connection SendToOrReceivedFrom;


public int MessageLength;


public CommandHeader Command;


public byte MainVersion;


public byte SecondVersion;




public string MessageBody;




public bool Sent;




public Message()






{


SendToOrReceivedFrom = null;


Sent = false;


}




public Message(CommandHeader command,byte mainVersion,byte secondVersion,string messageBody):this()

{


this.Command = command;


this.MainVersion = mainVersion;


this.SecondVersion = secondVersion;


this.MessageBody = messageBody;


}




public byte[] ToBytes()

{


this.MessageLength = 7 + SocketFactory.DefaultEncoding.GetByteCount(this.MessageBody);//计算消息总长度。消息头长度为7加上消息体的长度。


byte[] buffer = new byte[this.MessageLength];


//先将长度的4个字节写入到数组中。


BitConverter.GetBytes(this.MessageLength).CopyTo(buffer,0);


//将CommandHeader写入到数组中


buffer[4] = (byte)this.Command;


//将主版本号写入到数组中


buffer[5] = (byte)this.MainVersion;


//将次版本号写入到数组中


buffer[6] = (byte)this.SecondVersion;




//消息头已写完,现在写消息体。


byte[] body = new byte[this.MessageLength - 7];


SocketFactory.DefaultEncoding.GetBytes(this.MessageBody).CopyTo(buffer,7);


return buffer;


}




public static Message Parse(Connection connection)

{


Message message = new Message();


//先读出前四个字节,即Message长度


byte[] buffer = new byte[4];




if(connection.NetworkStream.DataAvailable)

{


int count = connection.NetworkStream.Read(buffer,0,4);




if(count == 4)

{


message.MessageLength = BitConverter.ToInt32(buffer,0);


}


else


throw new Exception("网络流长度不正确");


}


else


throw new Exception("目前网络不可读");


//读出消息的其它字节


buffer = new byte[message.MessageLength - 4];




if(connection.NetworkStream.DataAvailable)

{


int count = connection.NetworkStream.Read(buffer,0,buffer.Length);




if(count == message.MessageLength -4)

{


message.Command = (CommandHeader)buffer[0];


message.MainVersion = buffer[1];


message.SecondVersion = buffer[2];




//读出消息体


message.MessageBody = SocketFactory.DefaultEncoding.GetString(buffer,3,buffer.Length - 3);


message.SendToOrReceivedFrom = connection;




return message;


}


else


throw new Exception("网络流长度不正确");


}


else


throw new Exception("目前网络不可读");


}




}


}(5)、MessageCollection.cs文件中的代码:




MessageCollection.cs文件代码


using System;




namespace SocketLibrary






{


public class MessageCollection:System.Collections.CollectionBase






{


public MessageCollection()






{




}




public void Add(Message value)

{


List.Add(value);


}




public Message this[int index]

{




get

{


return List[index] as Message;


}




set

{


List[index] = value;


}


}




public MessageCollection this[Connection connection]

{




get

{


MessageCollection collection = new MessageCollection();




foreach(Message message in List)

{


if(message.SendToOrReceivedFrom == connection)


collection.Add(message);


}


return collection;


}


}


}


}(6)、Server.cs文件中的代码:




Server.cs文件代码


using System;


using System.Net;


using System.Net.Sockets;




namespace SocketLibrary






{


public class Server:SocketBase






{






private TcpListener _listener;


public Server()






{


this._connections = new ConnectionCollection();


}


protected System.Threading.Thread _listenConnection;






public void StartServer(int port)

{


_listener = new TcpListener(IPAddress.Any, port);


_listener.Start();




_listenConnection = new System.Threading.Thread(new System.Threading.ThreadStart(Start));


_listenConnection.Start();




this.StartListenAndSend();


}




public void StopServer()

{


_listenConnection.Abort();


this.EndListenAndSend();




}




private void Start()

{




try

{




while(true)

{




if(_listener.Pending())

{


TcpClient client = _listener.AcceptTcpClient();


NetworkStream stream = client.GetStream();


Connection connection = new Connection(stream);


this._connections.Add(connection);


this.OnConnected(this,new ConnectionEventArgs(connection,new Exception("连接成功")));


}


System.Threading.Thread.Sleep(200);


}


}




catch

{


}


}




}


}


(7)、SocketBase.cs文件中的代码:




SocketBase.cs文件代码


using System;




namespace SocketLibrary






{




/**//// <summary>


/// SocketBase 的摘要说明。


/// </summary>


public class SocketBase






{




public class MessageEventArgs:EventArgs

{


public Message Message;


public Connection Connecction;




public MessageEventArgs(Message message,Connection connection)

{


this.Message = message;


this.Connecction = connection;


}


}


public delegate void MessageEventHandler(object sender,MessageEventArgs e);






public class ConnectionEventArgs:EventArgs

{


public Connection Connection;


public Exception Exception;




public ConnectionEventArgs(Connection connection,Exception exception)

{


this.Connection = connection;


this.Exception = exception;


}


}


public delegate void ConnectionHandler(object sender,ConnectionEventArgs e);






public ConnectionCollection Connections

{




get

{return _connections;}




set

{_connections = value;}


}


protected ConnectionCollection _connections;






public MessageCollection messageQueue

{




get

{return _messageQueue;}




set

{_messageQueue = value;}


}


protected MessageCollection _messageQueue;




public SocketBase()






{


this._connections = new ConnectionCollection();


this._messageQueue = new MessageCollection();


}




protected void Send(Message message)

{


this.Send(message,message.SendToOrReceivedFrom);


}




protected void Send(Message message,Connection connection)

{


byte[] buffer = message.ToBytes();




lock(this)

{


connection.NetworkStream.Write(buffer,0,buffer.Length);


}


}




protected System.Threading.Thread _listenningthread;


protected System.Threading.Thread _sendthread;




protected virtual void Sendding()

{




try

{




while(true)

{


System.Threading.Thread.Sleep(200);




for(int i = 0 ; i < this.messageQueue.Count ; i++)

{




if(this.messageQueue[i].SendToOrReceivedFrom != null)

{


this.Send(this.messageQueue[i]);


this.OnMessageSent(this,new MessageEventArgs(this.messageQueue[i],this.messageQueue[i].SendToOrReceivedFrom));


}




else

{//对每一个连接都发送此消息




for(int j = 0 ; j < this.Connections.Count ; j++)

{


this.Send(this.messageQueue[i],this.Connections[j]);


this.OnMessageSent(this,new MessageEventArgs(this.messageQueue[i],this.Connections[j]));


}


}


this.messageQueue[i].Sent = true;


}


//清除所有已发送消息




for(int i = this.messageQueue.Count - 1 ; i > -1 ; i--)

{


if(this.messageQueue[i].Sent)


this.messageQueue.RemoveAt(i);


}


}




}catch

{


}


}




protected virtual void Listenning()

{




try

{




while(true)

{


System.Threading.Thread.Sleep(200);




foreach(Connection connection in this._connections)

{




if(connection.NetworkStream.CanRead && connection.NetworkStream.DataAvailable)

{




try

{


Message message = Message.Parse(connection);


this.OnMessageReceived(this,new MessageEventArgs(message,connection));


}




catch(Exception ex)

{


connection.NetworkStream.Close();


this.OnConnectionClose(this,new ConnectionEventArgs(connection,ex));


}


}


}


}


}




catch

{


}


}






protected void StartListenAndSend()

{


_listenningthread = new System.Threading.Thread(new System.Threading.ThreadStart(Listenning));


_listenningthread.Start();


_sendthread = new System.Threading.Thread(new System.Threading.ThreadStart(Sendding));


_sendthread.Start();


}




public void EndListenAndSend()

{


_listenningthread.Abort();


_sendthread.Abort();


}








public event MessageEventHandler MessageReceived;


public event MessageEventHandler MessageSent;


public event ConnectionHandler ConnectionClose;


public event ConnectionHandler Connected;






public void OnMessageReceived(object sender,MessageEventArgs e)

{


if(MessageReceived != null)


this.MessageReceived(sender,e);


}




public void OnMessageSent(object sender,MessageEventArgs e)

{


if(MessageSent != null)


this.MessageSent(sender,e);


}




public void OnConnectionClose(object sender,ConnectionEventArgs e)

{


if(ConnectionClose != null)


this.ConnectionClose(sender,e);


}




public void OnConnected(object sender,ConnectionEventArgs e)

{


if(Connected != null)


this.Connected(sender,e);


}


}


}(8)、SocketFactory.cs文件中的代码:




SocketFactory.cs文件代码


using System;


using System.Net;


using System.Net.Sockets;






namespace SocketLibrary

{




/**//// <summary>


/// 网络通信组件


/// </summary>




public class SocketFactory

{


public static System.Text.Encoding DefaultEncoding = System.Text.Encoding.GetEncoding("GB2312");


}


}4、将文件和代码建立和粘贴完成后,运行此类库,会在程序所在路径文件夹里的“bin/Debug/”下找到“SocketLibrary.dll”文件,下面开发的Windows服务就需要引用这个dll文件。

第二步再来开发出Windows服务。
1、打开Visual Studio.Net2003,单击菜单中的“文件”——>“新建”——>“项目”,在弹出的对话框左侧选择“Visual C#项目”,在右侧选择“Windows服务”,下方的名称中输入“SocketService”,位置自己随便选择一个路径。
2、删除自动创建的服务文件,新建如下的Windows服务文件“SocketService.cs”。
3、在SocketService.cs文件的设计界面,选择开发环境右侧的“属性”页卡,会在页卡底部发现“添加安装程序(I)”,单击此处后会在解决方案的SocketService工程下多一个服务文件“ProjectInstaller.cs”。
4、在ProjectInstaller.cs文件的设计界面,会看见两个组件“serviceProcessInstaller1”和“serviceInstaller1”。将serviceProcessInstaller1组件的Account属性设置为“LocalSystem”(表示本地系统服务,NetworkService表示网络服务,LocalService表示本地服务,User表示用户服务);再将serviceInstaller1组件的StartType属性设置为“Automatic”(表示服务自动启动,Manual表示手动启动,Disabled表示禁用)。
5、右击解决方案中的“引用”,选择添加引用,在弹出的对话框中选择“浏览”,将前面的“SocketLibrary.dll”添加到此引用。
6、在系统C盘下建立两个文件“SocketService.ini”和“SocketService.log”。SocketService.ini文件是配置SocketService监听的端口号,打开该ini文件在其中编辑下面的内容“端口号:8088”(双引号请不要输入在ini文件的内容里),而SocketService.log是为了记录有关信息的日志。
7、删除SocketService.cs文件的所有代码,将下面的代码拷贝到该文件中:




SocketService.cs文件代码


using System;


using System.Collections;


using System.ComponentModel;


using System.Data;


using System.Diagnostics;


using System.ServiceProcess;


using System.IO;


using SocketLibrary;




namespace SocketService






{


public class SocketService : System.ServiceProcess.ServiceBase






{




/**//// <summary>


/// 必需的设计器变量。


/// </summary>


private System.ComponentModel.Container components = null;




public SocketService()






{


// 该调用是 Windows.Forms 组件设计器所必需的。


InitializeComponent();




// TODO: 在 InitComponent 调用后添加任何初始化


}






组件设计器生成的代码#region 组件设计器生成的代码




/**//// <summary>


/// 设计器支持所需的方法 - 不要使用代码编辑器


/// 修改此方法的内容。


/// </summary>


private void InitializeComponent()






{


//


// SocketService


//


this.ServiceName = "SocketService";




}


#endregion






/**//// <summary>


/// 清理所有正在使用的资源。


/// </summary>


protected override void Dispose( bool disposing )






{


if( disposing )






{


if (components != null)






{


components.Dispose();


}


}


base.Dispose( disposing );


}






/**//// <summary>


/// 应用程序的主入口点。


/// </summary>


[STAThread]


static void Main()






{


System.ServiceProcess.ServiceBase.Run(new SocketService());


}




SocketLibrary.Server _server = new SocketLibrary.Server();






/**//// <summary>


/// 设置具体的操作,以便服务可以执行它的工作。


/// </summary>


protected override void OnStart(string[] args)






{


// TODO: 在此处添加代码以启动服务。


try






{


StreamReader ConfigReader = new StreamReader("C://SocketService.ini",System.Text.Encoding.GetEncoding("GB2312"));


string str = ConfigReader.ReadToEnd();


string[] Str = str.Split(':');


if (Str.Length == 2)






{


if(Str[0] == "端口号")






{




_server.StartServer(Convert.ToInt32(Str[1]));


StreamWriter LogWriter = new StreamWriter("C://SocketService.log",true,System.Text.Encoding.GetEncoding("GB2312"));


LogWriter.Write(DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToShortTimeString() + " SocketService服务已启动/n");


LogWriter.Close();


_server.MessageReceived += new SocketLibrary.SocketBase.MessageEventHandler(_server_MessageReceived);


_server.Connected += new SocketLibrary.SocketBase.ConnectionHandler(_server_Connected);


}


else






{


StreamWriter LogWriter = new StreamWriter("C://SocketService.log",true,System.Text.Encoding.GetEncoding("GB2312"));


LogWriter.Write(DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToShortTimeString() + " SocketService.ini文件中无端口号属性,格式应为/"端口号:[输入的端口号]/"/n");


LogWriter.Close();


OnStop();


}


}


else






{


StreamWriter LogWriter = new StreamWriter("C://SocketService.log",true,System.Text.Encoding.GetEncoding("GB2312"));


LogWriter.Write(DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToShortTimeString() + " SocketService.ini文件中属性过多,格式应为/"端口号:[输入的端口号]/"/n");


LogWriter.Close();


OnStop();


}


}


catch (Exception e)






{


StreamWriter LogWriter = new StreamWriter("C://SocketService.log",true,System.Text.Encoding.GetEncoding("GB2312"));


LogWriter.Write(DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToShortTimeString() + " SocketService服务启动时有错误,错误信息:" + e.Message + "/n");


LogWriter.Close();


OnStop();


}




}






/**//// <summary>


/// 停止此服务。


/// </summary>


protected override void OnStop()






{


// TODO: 在此处添加代码以执行停止服务所需的关闭操作。


_server.StopServer();


StreamWriter LogWriter = new StreamWriter("C://SocketService.log",true,System.Text.Encoding.GetEncoding("GB2312"));


LogWriter.Write(DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToShortTimeString() + " SocketService服务已停止/n");


LogWriter.Close();


}




private void _server_MessageReceived(object sender, SocketLibrary.SocketBase.MessageEventArgs e)






{


StreamWriter LogWriter = new StreamWriter("C://SocketService.log",true,System.Text.Encoding.GetEncoding("GB2312"));


LogWriter.Write(DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToShortTimeString() + " " + e.Message.MessageBody + "/n");


LogWriter.Close();


}


private void _server_Connected(object sender, SocketLibrary.SocketBase.ConnectionEventArgs e)






{


StreamWriter LogWriter = new StreamWriter("C://SocketService.log",true,System.Text.Encoding.GetEncoding("GB2312"));


LogWriter.Write(DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToShortTimeString() + " " + e.Exception.Message + "/n");


LogWriter.Close();


}


}


}8、在Visual Studio.Net2003的菜单上选择“生成”——>“重新生成解决方案”,当生成成功后,会在程序所在路径文件夹里的“bin/Debug/”下找到“SocketService.exe”文件,记住这个路径和文件名,下一步需要用到。
9、打开“Visual Studio .NET 2003 命令提示”(应该都知道如何打开吧,不知道的可以在评论中询问)。在其中输入“installutil [第8步中的路径和文件名]”(例如:installutil C:/SocketService/bin/Debug/SocketService.exe),按下回车,将会在本机上安装刚开发好的Windows服务,如果要卸载安装过的Windows服务请在“Visual Studio .NET 2003 命令提示”中输入“installutil /u [第8步中的路径和文件名]”(例如:installutil /u C:/SocketService/bin/Debug/SocketService.exe)。
10、制作Windows服务的安装部署工程(略)。

第三步最后开发出一个Socket通信的客户端来验证此服务。
1、和以往建立C/S程序的过程一样,只是将工程名称改为“SocketClientTest”。
2、删除自动创建的Form1,新建窗体“CFrom”。
3、窗体控件与布局见下图:



4、在引用中添加“SocketLibrary.dll”引用(添加方法和SocketService工程添加方法相同)
5、后台代码如下:




CForm.cs文件代码


using System;


using System.Drawing;


using System.Collections;


using System.ComponentModel;


using System.Windows.Forms;


using System.Data;




namespace SocketClientTest






{




/**//// <summary>


/// Form1 的摘要说明。


/// </summary>


public class CForm : System.Windows.Forms.Form






{




/**//// <summary>


/// 必需的设计器变量。


/// </summary>


private System.ComponentModel.Container components = null;




public CForm()






{


//


// Windows 窗体设计器支持所必需的


//


InitializeComponent();




//


// TODO: 在 InitializeComponent 调用后添加任何构造函数代码


//


}






/**//// <summary>


/// 清理所有正在使用的资源。


/// </summary>


protected override void Dispose( bool disposing )






{


if( disposing )






{


if (components != null)






{


components.Dispose();


}


}


base.Dispose( disposing );


}






Windows 窗体设计器生成的代码#region Windows 窗体设计器生成的代码




/**//// <summary>


/// 设计器支持所需的方法 - 不要使用代码编辑器修改


/// 此方法的内容。


/// </summary>


private void InitializeComponent()






{


this.button1 = new System.Windows.Forms.Button();


this.textBox1 = new System.Windows.Forms.TextBox();


this.button2 = new System.Windows.Forms.Button();


this.button3 = new System.Windows.Forms.Button();


this.SuspendLayout();


//


// button1


//


this.button1.Location = new System.Drawing.Point(40, 24);


this.button1.Name = "button1";


this.button1.TabIndex = 0;


this.button1.Text = "连接";


this.button1.Click += new System.EventHandler(this.button1_Click);


//


// textBox1


//


this.textBox1.Location = new System.Drawing.Point(24, 80);


this.textBox1.Name = "textBox1";


this.textBox1.TabIndex = 1;


this.textBox1.Text = "textBox1";


//


// button2


//


this.button2.Location = new System.Drawing.Point(144, 80);


this.button2.Name = "button2";


this.button2.TabIndex = 2;


this.button2.Text = "发送";


this.button2.Click += new System.EventHandler(this.button2_Click);


//


// button3


//


this.button3.Location = new System.Drawing.Point(144, 24);


this.button3.Name = "button3";


this.button3.TabIndex = 3;


this.button3.Text = "停止";


this.button3.Click += new System.EventHandler(this.button3_Click);


//


// Form1


//


this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);


this.ClientSize = new System.Drawing.Size(292, 126);


this.Controls.Add(this.button3);


this.Controls.Add(this.button2);


this.Controls.Add(this.textBox1);


this.Controls.Add(this.button1);


this.Name = "CForm";


this.Text = "CForm";


this.Load += new System.EventHandler(this.CForm_Load);


this.ResumeLayout(false);




}


#endregion






/**//// <summary>


/// 应用程序的主入口点。


/// </summary>


[STAThread]


static void Main()






{


Application.Run(new CForm());


}




private System.Windows.Forms.Button button1;


private System.Windows.Forms.TextBox textBox1;


private System.Windows.Forms.Button button2;


private System.Windows.Forms.Button button3;


SocketLibrary.Client client;


private void CForm_Load(object sender, System.EventArgs e)






{


client = new SocketLibrary.Client();




SocketLibrary.SocketFactory factory = new SocketLibrary.SocketFactory();


}






private void button1_Click(object sender, System.EventArgs e)

{


client.StartClient(System.Net.IPAddress.Parse("192.168.5.9"),8088);//此处输入自己的计算机IP地址,端口需和SocketService.ini中的端口号一样


}






private void button2_Click(object sender, System.EventArgs e)

{


SocketLibrary.Message message = new SocketLibrary.Message(SocketLibrary.Message.CommandHeader.SendMessage,1,1,textBox1.Text);


client.messageQueue.Add(message);


}






private void button3_Click(object sender, System.EventArgs e)

{


client.StopClient();


}


}


}
6、运行程序,点击CForm中的“连接”按钮,再在TextBox1中输入部分信息,单击“发送”按钮,看看在C:/SocketService.log中是否记录了CForm窗口中TextBox1中的内容。

到此我们就已经将这个Socket通信Server端的Winodows服务开发完成了。下面提供源程序的下载:

本地下载 SocketLibrary类库源码

本地下载 Server端Socket通信Windows服务源码

本地下载 SocketClientTest源码

本地下载 SocketServerTest源码(没有改变为Windows服务时的程序,即下载时的原程序)

以上程序已在在Visual Studio.Net2003下运行通过。

最近发现,此Socket程序的一个问题,就是此Socket程序用自己的Socket的Client端测试没有问题,但是用其他的普通Socket就会出现收不到消息包,但是连接是被建立的。主要问题出现在Message.cs文件中,为此更改了此文件的部分代码,以便能够在客户端和服务端接收通用的Socket消息包。
更改Message.cs文件中的代码如下:




更改Message.cs文件中的代码


using System;


using System.IO;




namespace SocketLibrary






{


public class Message






{


public Connection SendToOrReceivedFrom;


public int MessageLength;


public string MessageBody;




public bool Sent;




public Message()






{


SendToOrReceivedFrom = null;


Sent = false;


}




public Message(string messageBody):this()






{


this.MessageBody = messageBody;


}




public byte[] ToBytes()






{


this.MessageLength = SocketFactory.DefaultEncoding.GetByteCount(this.MessageBody);//计算消息体的长度。


byte[] buffer = new byte[this.MessageLength];


buffer = SocketFactory.DefaultEncoding.GetBytes(this.MessageBody);


return buffer;


}




public static Message Parse(Connection connection)






{


Message message = new Message();


byte[] bt = new byte[1024];


if(connection.NetworkStream.DataAvailable)






{


int count = connection.NetworkStream.Read(bt,0,1024);


if(count < 1024)






{


byte[] buffer = new byte[count];


int i = 0;


while(i < count)






{


buffer[i] = bt[i];


i++;


}


//读出消息体


message.MessageBody = SocketFactory.DefaultEncoding.GetString(buffer,0,buffer.Length);


message.SendToOrReceivedFrom = connection;


return message;


}


else






{


throw new Exception("网络流长度不正确");


}


}


else


throw new Exception("目前网络不可读");


}


}


}



约束Socket消息包的消息体内容不能超过1024字节。

经过实际应用发现此Socket程序存在的问题还真不少,就是改为我前一个更正评论后也仍然有问题存在,虽然可以收到通用的Socket消息包了,但是程序在长时间接收大量客户端发来的消息后,会出现只有连接成功,而不再接收连接后的消息包,分析其原因,主要错误的设计如下两个地方:
1、采用两个线程。一个线程是用来连接客户机并取得消息流内容放入自己定义的NetworkStream流中;另一个则是从NetworkStream流中读取消息体。
2、使用了自定义的NetworkStream流,而这个流却被用在两个不同的线程中,每个线程的休眠时间为200ms。
现在我们分析出了错误的地方,那么就需要找到解决方法,我们现在将判断连接和读取NetworkStream流都放在一个线程里完成,而不要分为两个线程。

需要更改的文件有SocketBase.cs、Server.cs和Client.cs。
更改SocketBase.cs文件中的代码如下:




更改SocketBase.cs文件中的代码


using System;




namespace SocketLibrary






{




/**//// <summary>


/// SocketBase 的摘要说明。


/// </summary>


public class SocketBase






{




public class MessageEventArgs:EventArgs

{


public Message Message;


public Connection Connecction;




public MessageEventArgs(Message message,Connection connection)

{


this.Message = message;


this.Connecction = connection;


}


}


public delegate void MessageEventHandler(object sender,MessageEventArgs e);






public class ConnectionEventArgs:EventArgs

{


public Connection Connection;


public Exception Exception;




public ConnectionEventArgs(Connection connection,Exception exception)

{


this.Connection = connection;


this.Exception = exception;


}


}


public delegate void ConnectionHandler(object sender,ConnectionEventArgs e);






public ConnectionCollection Connections

{




get

{return _connections;}




set

{_connections = value;}


}


protected ConnectionCollection _connections;






public MessageCollection messageQueue

{




get

{return _messageQueue;}




set

{_messageQueue = value;}


}


protected MessageCollection _messageQueue;




public SocketBase()






{


this._connections = new ConnectionCollection();


this._messageQueue = new MessageCollection();


}




protected void Send(Message message)

{


this.Send(message,message.SendToOrReceivedFrom);


}




protected void Send(Message message,Connection connection)

{


byte[] buffer = message.ToBytes();




lock(this)

{


connection.NetworkStream.Write(buffer,0,buffer.Length);


}


}




protected System.Threading.Thread _listenningthread;


protected System.Threading.Thread _sendthread;




protected virtual void Sendding()

{




try

{




while(true)

{




for(int i = 0 ; i < this.messageQueue.Count ; i++)

{




if(this.messageQueue[i].SendToOrReceivedFrom != null)

{


this.Send(this.messageQueue[i]);


this.OnMessageSent(this,new MessageEventArgs(this.messageQueue[i],this.messageQueue[i].SendToOrReceivedFrom));


}




else

{//对每一个连接都发送此消息




for(int j = 0 ; j < this.Connections.Count ; j++)

{


this.Send(this.messageQueue[i],this.Connections[j]);


this.OnMessageSent(this,new MessageEventArgs(this.messageQueue[i],this.Connections[j]));


}


}


this.messageQueue[i].Sent = true;


}


//清除所有已发送消息




for(int i = this.messageQueue.Count - 1 ; i > -1 ; i--)

{


if(this.messageQueue[i].Sent)


this.messageQueue.RemoveAt(i);


}


System.Threading.Thread.Sleep(50);


}




}catch

{


}


}




public event MessageEventHandler MessageReceived;


public event MessageEventHandler MessageSent;


public event ConnectionHandler ConnectionClose;


public event ConnectionHandler Connected;






public void OnMessageReceived(object sender,MessageEventArgs e)

{


if(MessageReceived != null)


this.MessageReceived(sender,e);


}




public void OnMessageSent(object sender,MessageEventArgs e)

{


if(MessageSent != null)


this.MessageSent(sender,e);


}




public void OnConnectionClose(object sender,ConnectionEventArgs e)

{


if(ConnectionClose != null)


this.ConnectionClose(sender,e);


}




public void OnConnected(object sender,ConnectionEventArgs e)

{


if(Connected != null)


this.Connected(sender,e);


}


}


}
更改Server.cs文件中的代码如下:




更改Server.cs文件中的代码


using System;


using System.Net;


using System.Net.Sockets;




namespace SocketLibrary






{


public class Server:SocketBase






{






private TcpListener _listener;


public Server()






{


this._connections = new ConnectionCollection();


}


protected System.Threading.Thread _listenConnection;






public void StartServer(int port)

{


_listener = new TcpListener(IPAddress.Any, port);


_listener.Start();




_listenConnection = new System.Threading.Thread(new System.Threading.ThreadStart(Start));


_listenConnection.Start();


}




public void StopServer()

{


_listenConnection.Abort();


}




private void Start()

{




try

{




while(true)

{




if(_listener.Pending())

{


TcpClient client = _listener.AcceptTcpClient();


NetworkStream stream = client.GetStream();


Connection connection = new Connection(stream);


this._connections.Add(connection);


this.OnConnected(this,new ConnectionEventArgs(connection,new Exception("连接成功")));


if(connection.NetworkStream.CanRead && connection.NetworkStream.DataAvailable)






{


try






{


Message message = Message.Parse(connection);


this.OnMessageReceived(this,new MessageEventArgs(message,connection));


}


catch(Exception ex)






{


connection.NetworkStream.Close();


this.OnConnectionClose(this,new ConnectionEventArgs(connection,ex));


}


}


}


System.Threading.Thread.Sleep(50);


}


}




catch

{


}


}




}


}

更改Client.cs文件中的代码如下:




更改Client.cs文件中的代码


using System;


using System.Net;


using System.Net.Sockets;




namespace SocketLibrary






{




public class Client:SocketBase






{


public const int CONNECTTIMEOUT = 10;


public Client()






{




}




public Connection StartClient(IPAddress ipaddress,int port)

{


TcpClient client = new TcpClient();


client.SendTimeout = CONNECTTIMEOUT;


client.ReceiveTimeout = CONNECTTIMEOUT;




client.Connect(ipaddress,port);




this._connections.Add(new Connection(client.GetStream()));


return new Connection(client.GetStream());


}


}


}



作品说明:

作者:刚刚

最初本人发表本作品网址:/content/3769353.html

郑重声明:

最近“刚刚”本人发现网络中有个别人将此文章当作原创发布在了自己在CSDN等网站上的博客里,现特别说明本文的原创地址与作者为上述“作品说明”,其他网站或个人博客中的原创标识都不足以相信为真的原创含义。请尊重网络作品转载等方式方法的著作版权!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐