[朝花夕拾]基于C#的模拟仿真平台设计(部分)及服务器异步通信代码
来源:互联网 发布:java如何进行异常处理 编辑:程序博客网 时间:2024/04/30 06:28
开发环境: .net 4.5
开发语言: C#
平台架构:C-S架构
数据库: MariaDB
插件:Ribbon UI、DotNetBar
一,服务器端总体设计
根据项目需求将平台设计分为以下模块:
a) 显示信息模块
b) 用户信息管理模块
c) 配置模块
d) 与客户端通信模块
e) 数据库模块
f) 结果处理模块
g) 仿真软件控制模块
二,服务器端架构
服务器端由于两种仿真软件对操作系统的不同要求,和文件管理和数据安全方面的考虑,故使用三个服务器端,其中两个作为计算服务器,另一个作为存储服务器使用。
三,与客户端通信模块
本项目使用异步通信模式,并制定了一套通信方案,发送的信息使用UTF-8编码格式:
a) 通信内容开始符(2byte):##,识别通信内容开始
b) 通信内容大小(4byte):构造完成正文部分后填写数据包大小的int数值以验证传输数据是否正确
c) 通信内容结束符(2byte):$$,识别通信内容结束
d) 通信内容正文(不定,构造完成后确定长度)
e) 通信内容形式:命令|参数|参数|….其中参数的个数以及含义依据命令的不同来构造生成。
四,仿真软件控制模块
当客户端发出了执行仿真软件的命令时,服务器:
a) 开启一个子线程(守护线程,在服务端版Socket编程需要处理长时间没有发送数据的Socket,需要在超时多长时间后断开连接,我们需要独立一个线程(DaemonThread)来轮询,在执行断开时,需要把Socket对象锁定,并调用CloseClientSocket来断开连接)来负责处理仿真软件脚本,并将信息添加到数据库中。
b) 分别执行发送过来的几个脚本,并使用子线程监控脚本运行状态。
c) 当执行成功后将脚本文件、结果文件等相关文件上传到存储服务器,并更新数据库。
对于不能并发执行的仿真软件,设置一个脚本对象的队列。当执行脚本空闲并且队列中有脚本时,弹出第一个脚本进行执行。
五,异步通信模块代码
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Net.Sockets;using System.Net;using System.Windows.Forms;using System.Threading;using System.Data;using System.IO;namespace server2014{ public class SocketServer { public static string msgstr = " "; // Thread signal. public static ManualResetEvent allDone = new ManualResetEvent(false); public SocketServer() { //初始化SOCKET实例 ListenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); ListenSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); //初始化终结点实例 localEP = new IPEndPoint(IPAddress.Any, setPort); } //监听网络连接的socket public Socket ListenSocket = null; //监听端口 public int localPort = 9999; //监听节点 public IPEndPoint localEP = null; //进行网络监听的线程 public Thread ListeningThread = null; //SOCKET,用于等待其它客户端的连接 Socket server = null; //负责与客户端进行通信的socket Socket ClientSocket = null; //用来设置服务端监听的端口号 public int setPort { get { return localPort; } set { localPort = value; } } //新建线程,进行网络监听 public void startListenThread() { //新建一个委托线程 ThreadStart myThreadDelegate = new ThreadStart(Listen); //实例化新线程 ListeningThread = new Thread(myThreadDelegate); ListeningThread.IsBackground = true; ListeningThread.Start(); } //终止监听线程 public void stopListenThread() { if (ListeningThread != null) { ListeningThread.Abort(); } } //监听函数 private void Listen() { setPort = 9999; try { //绑定 ListenSocket.Bind(localEP); //监听 ListenSocket.Listen(10); //开始接受异步连接 ListenSocket.BeginAccept(new AsyncCallback(OnConnectRequest), ListenSocket); } catch (Exception e) { MessageBox.Show("开启监听服务失败!\n失败原因:" + e.Message); Users.writeLog(MainForm.dailylogPath, DateTime.Now.ToString() + " 端口" + localPort + " 开启监听服务失败"); } } //当有客户端连接时的处理 public void OnConnectRequest(IAsyncResult ar) { string ip =""; string ipmsgstr=""; //接收的客户端传送过来的数据 byte[] receiveData = new byte[1024]; byte[] senddata = null; try { //初始化一个SOCKET,用于等待其它客户端的连接 server = (Socket)ar.AsyncState; server.BeginAccept(new AsyncCallback(OnConnectRequest), server); //负责与客户端进行通信的socket ClientSocket = server.EndAccept(ar); //获取客户端的IP和端口 ip = ClientSocket.RemoteEndPoint.ToString(); ipmsgstr = ip + " "; } catch { MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "网络错误!" + "\r\n"); } //负责接收客户端信息 while (true) { int recv = 0; try { recv = ClientSocket.Receive(receiveData); //对传输过来的数据进行解析 byte[] effemsg = Protocol.SubByteArray(receiveData, 0, recv); string[] parameters = Protocol.anaMsg(effemsg); int per = 0;//判断权限 int[] perpass = { 0, 0 }; //根据协议命令的不同进行不同的处理 switch (parameters[0]) { case "-1": //协议解析出错,断开连接 try { //断开连接 ClientSocket.Disconnect(true); MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "与客户端断开连接! " + "\r\n"); return; } catch (Exception e) { MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "网络错误!" + "\r\n"); return; } case "0": //查看服务器端执行的所有任务 perpass = Business.check(parameters[1], parameters[2]); per = perpass[1]; if (perpass[0] > 0) { //用户名密码验证成功则添加用户 //Business.addUser(parameters[1], parameters[2]); Business.loginUser(parameters[1], parameters[2]); string sendstring = Business.getAllTasks(); senddata = Protocol.getLookReturnMsg(sendstring); try { MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "用户" + parameters[1] + "查看服务器运行状况。" + "\r\n"); ClientSocket.Send(senddata); } catch (Exception e) { MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "网络错误!" + e.Message + "\r\n"); } } else { MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "用户" + parameters[1] + "查看服务器运行状况时密码验证失败!" + "\r\n"); senddata = Protocol.getCheckReturnMsg(parameters[1], per.ToString(), false); try { ClientSocket.Send(senddata); } catch (Exception e) { MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "网络错误!" + e.Message + "\r\n"); } } break; case "1": //验证客户端用户名密码 perpass = Business.check(parameters[1], parameters[2]); per = perpass[1]; if (perpass[0] > 0) { MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "用户" + parameters[1] + "登录成功!" + "\r\n"); Users.writeLog(MainForm.dailylogPath, DateTime.Now.ToString() + " " + ip + " 用户 " + parameters[1] + " 登录成功!"); LoginForm.users.ftpupdown.MakeDir(parameters[1]); //用户名密码验证成功则添加用户 //Business.addLoginUser(parameters[1]); //Business.addUser(parameters[1], parameters[2]); Business.loginUser(parameters[1], parameters[2]); string serveru = Config.getparameter("Serveru"); string ansysPath = Config.getparameter("ansysProgramPath"); DatabaseTools db = Users.databaseTools4; List<string> tasklist = new List<string>(); string userpath = Users.ftpServerpath + "\\" + parameters[1]; Users.creatDirtionary(userpath); db.queryTaskByUsername(parameters[1], tasklist); foreach (string taskname in tasklist) { string taskpath = userpath + "\\" + taskname; Users.creatDirtionary(taskpath); for (int i = 1; i < 4; i++) { //i为脚本类型 string kindpath = taskpath + "\\" + Users.scriptKindTrans(i); Users.creatDirtionary(kindpath); List<string> scriptsList = new List<string>(); Users.databaseTools.queryScriptByUserTaskname(parameters[1], taskname, i, 3, scriptsList); foreach (string scriptname in scriptsList) { string scriptpath = kindpath + "\\" + scriptname; Users.creatDirtionary(scriptpath); string sciptfilepath = scriptpath + "\\script"; Users.creatDirtionary(sciptfilepath); string scipttemppath = scriptpath + "\\temp"; Users.creatDirtionary(scipttemppath); string sciptresultpath = scriptpath + "\\result"; Users.creatDirtionary(sciptresultpath); } } } List<string> taskAndUpdateList = new List<string>(); db.queryTaskAndUpdateByUsername(parameters[1], taskAndUpdateList); senddata = Protocol.getLoginCheckReturnMsg(parameters[1], serveru,ansysPath, taskAndUpdateList, per.ToString(), true); //将客户端查询时间记录到txt文本中 foreach (string taskname in tasklist) { string taskpath = userpath + "\\" + taskname; Users.writeClientLogin(taskpath + "\\taskLastQuery.txt", DateTime.Now.ToString()); } try { ClientSocket.Send(senddata); } catch (Exception e) { MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "网络错误!" + e.Message + "\r\n"); } } else { MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "用户" + parameters[1] + "登录失败!" + "\r\n"); //senddata = Protocol.getCheckReturnMsg(parameters[1], per.ToString(),false); senddata = Protocol.getLoginCheckReturnMsg(parameters[1], "","", new List<string>(), per.ToString(), false); try { ClientSocket.Send(senddata); } catch (Exception e) { MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "网络错误!" + e.Message + "\r\n"); } } break; case "2": //添加新的脚本并且执行 Business.loginUser(parameters[1], parameters[2]); MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "用户" + parameters[1] + "执行任务" + parameters[3] + "的脚本程序" + parameters[4] + "\r\n"); try { //将新的任务保存到USERS中 LoginForm.users.addTask(parameters[1], parameters[3]); LoginForm.users.addScript(parameters[1], parameters[3], parameters[4], int.Parse(parameters[5])); //执行新的任务,执行脚本 //------------------------------------------------------------------ bool executeflag = false; //执行是否成功 //执行脚本的总次数 int projectcount = int.Parse(parameters[6]); //当前执行脚本的数量 int projecttemp = 0; if (int.Parse(parameters[5]) == 2) { Users.databaseTools.updateScriptState(parameters[1], parameters[3], parameters[4], 2); string xmlpath = Users.ftpServerpath + "\\" + parameters[1] + "\\" + parameters[3] + "\\test\\" + parameters[4] + "\\" + parameters[4] + ".xml"; string curxmlpath = Users.ftpServerpath + "\\" + parameters[1] + "\\" + parameters[3] + "\\test\\" + parameters[4] + "\\temp\\" + parameters[4] + ".xml"; File.Copy(curxmlpath, xmlpath, true); for (; projecttemp < projectcount; projecttemp++) { executeflag = Business.executeScript(parameters[1], parameters[3], parameters[4], int.Parse(parameters[5]), projecttemp, projectcount); Thread.CurrentThread.Join(1000); } } else if (int.Parse(parameters[5]) == 1) { executeflag = Business.executeScript(parameters[1], parameters[3], parameters[4], int.Parse(parameters[5]), projecttemp, projectcount); } else if (int.Parse(parameters[5]) == 3) { executeflag = Business.executeScript(parameters[1], parameters[3], parameters[4], int.Parse(parameters[5]), projecttemp, projectcount); //更改脚本状态为运行 Users.databaseTools.updateScriptState(parameters[1], parameters[3], parameters[4], 2); } //------------------------------------------------------------------ //bool executeflag = Business.executeScript(parameters[1], parameters[3], parameters[4], int.Parse(parameters[5])); //Users.checkAddsettings(); senddata = Protocol.getExecuteReturnMsg(parameters[1], parameters[3], parameters[4], executeflag); } catch (Exception e) { MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "用户" + parameters[1] + "执行任务" + parameters[3] + "的脚本程序" + parameters[4] + "错误!\r\n"); } try { ClientSocket.Send(senddata); } catch (Exception e) { MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "网络错误!" + e.Message + "\r\n"); } break; case "3": //查询某一任务中某一个脚本的状态 Business.loginUser(parameters[1], parameters[2]); //查询任务下某一脚本状态 MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "用户" + parameters[1] + "查询任务" + parameters[3] + "的脚本程序" + parameters[4] + "的执行状态。\r\n"); //查询任务之中某一个脚本的状态 scriptStates scriptstate = LoginForm.users.queryScriptState(parameters[1], parameters[3], parameters[4], int.Parse(parameters[5])); //返回任务状态 senddata = Protocol.getQueryReturnMsg(parameters[1], parameters[3], parameters[4], scriptstate.ToString(), parameters[5]); try { ClientSocket.Send(senddata); } catch (Exception e) { MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "网络错误!" + e.Message + "\r\n"); } break; case "4": //删除某一任务的执行 Business.loginUser(parameters[1], parameters[2]); //删除任务 int deleteflag = Users.databaseTools4.deleteTask(parameters[1], parameters[2]); if (deleteflag > 0) { MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "用户" + parameters[1] + "删除任务" + parameters[2] + "成功。\r\n"); } else { MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "用户" + parameters[1] + "删除任务" + parameters[2] + "失败。\r\n"); } //返回任务状态 senddata = Protocol.getTdeleteReturnMsg(parameters[1], parameters[2], deleteflag.ToString()); try { ClientSocket.Send(senddata); } catch (Exception e) { MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "网络错误!" + "\r\n"); } break; case "5": Business.loginUser(parameters[1], parameters[2]); MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "用户" + parameters[1] + "查询任务" + parameters[3] + "下脚本信息。\r\n"); //任务 DataTable dt1 = Users.queryScriptMessage(parameters[1], parameters[3], new string[] { "scriptname", "scriptkind", "scriptstate" }); bool queryTaskFlag = true; //返回任务状态 senddata = Protocol.getQueryTaskReturnMsg(parameters[1], parameters[3], dt1, queryTaskFlag); try { ClientSocket.Send(senddata); } catch (Exception e) { MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "网络错误!" + "\r\n"); } break; case "6": if (int.Parse(parameters[1]) == 1) { Users.databaseTools4.addMaterial(parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], parameters[10], parameters[11], parameters[12], parameters[13], parameters[14], parameters[15], parameters[16], parameters[17], parameters[18], parameters[19], parameters[20]); MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "用户" + parameters[1] + "添加材料" + parameters[3] + "。\r\n"); } else if (int.Parse(parameters[1]) == 2) { Users.databaseTools4.deleteMaterial(parameters[2]); MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "用户" + parameters[1] + "删除材料" + parameters[2] + "。\r\n"); } else if (int.Parse(parameters[1]) == 3) { Users.databaseTools4.updateMaterial(parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], parameters[10], parameters[11], parameters[12], parameters[13], parameters[14], parameters[15], parameters[16], parameters[17], parameters[18], parameters[19], parameters[20]); MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "用户" + parameters[1] + "修改材料" + parameters[3] + "。\r\n"); } else if (int.Parse(parameters[1]) == 4) { MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "用户" + parameters[1] + "查询材料。\r\n"); } DataTable dt = new DataTable(); Users.databaseTools4.queryMaterial(0 + "", dt); //dt.Rows[0][1]; senddata = Protocol.getMaterialReturnMsg(dt); try { ClientSocket.Send(senddata); } catch (Exception e) { MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "网络错误!" + "\r\n"); } break; } } catch (SocketException e) { MainForm.mainfrm.messageShow(DateTime.Now.ToString() + msgstr + ipmsgstr + "网络错误! " + "\r\n"); return; } finally { } } } }}
- [朝花夕拾]基于C#的模拟仿真平台设计(部分)及服务器异步通信代码
- 基于Boost.Asio的异步通信服务器设计与开发
- C#中的异步调用及异步设计模式(三)——基于事件的异步模式
- C#中的异步调用及异步设计模式(三)——基于事件的异步模式
- C#中的异步调用及异步设计模式(三)——基于事件的异步模式
- C#中的异步调用及异步设计模式(三)——基于事件的异步模式
- C#中的异步调用及异步设计模式(二)——基于 IAsyncResult 的异步设计模式
- C#中的异步调用及异步设计模式(二)——基于 IAsyncResult 的异步设计模式
- C#中的异步调用及异步设计模式(二)——基于 IAsyncResult 的异步设计模式
- 基于win平台的高性能服务器底层通信模型设计(1)
- 基于win平台的高性能服务器底层通信模型设计(1)
- 基于win平台的高性能服务器底层通信模型设计(1)
- 基于win平台的高性能服务器底层通信模型设计(1)
- 基于win平台的高性能服务器底层通信模型设计(1)
- 基于win平台的高性能服务器底层通信模型设计(1)
- 基于win平台的高性能服务器底层通信模型设计(1)
- 基于win平台的高性能服务器底层通信模型设计(1)
- 基于win平台的高性能服务器底层通信模型设计(1)
- DIV重叠 CSS让DIV层叠 两个DIV或多个DIV顺序重叠加
- 计数排序
- iOS编程(3)NavigationController
- [jvm解析系列][十]类加载器和双亲委派模型,你真的了解ClassLoader吗?
- Spark定制班第22课:Spark Streaming架构源码图解
- [朝花夕拾]基于C#的模拟仿真平台设计(部分)及服务器异步通信代码
- 第十六周阅读项目-8
- NC开发中 一些bug总结
- vc精确控制时间
- JZOJ.3431【GDOI2014模拟】网格 解题报告
- 生成debug.keystire
- 如何使用JSTL
- 配合Python3.5怎么成功安装64位的Pygame?
- html <input>