一、界面设计
在做软件之前使用“软件界面设计工具”先设计并绘制出软件界面,方便在写代码之前确认“功能需求”以及“交互流程”。
这里使用的软件是:“Axure RP”
二、新建工程与绘制界面
-
新建工程:
使用任意一个Visual studio即可,这里使用Visual studio2017作为开发环境(安装的时候选择.net桌面开发)。新建工程选择“c# winform类型的工程,然后填写工程名字即可完成工程创建”。
-
绘制图形界面:
鼠标单击打开“From1.cs”文件,会出现界面绘制界面。点击软件左侧栏的“工具栏”弹出界面控件列表,选择要绘制的控件拖动到软件绘制界面,并调整控件位置,直到达到设计图所设计的样子。如下图所示:
-
添加按钮按下相应函数:
选中按钮并使用右键点击“属性”,从而打开这个按钮的属性配置窗口,在窗口里可以设置很多属性,切换到事件配置页面(闪电图标)即可编辑与此控件相关的事件。在“事件配置页面”即可给按钮添加点击事件响应函数,如下图所示:
三、用到的库函数说明
.net提供了串口编程函数类,为了避免把逻辑代码和界面代码混合编写。这里给串口相关操作函数做了二次封装(采用类似工厂模型建立)。界面代码只要调用二次封装的类即可完成网络通信。
- Udp broadcast
UdpClient { //.net提供的类
UdpClient();//新建对象即可使用,没有Open函数
bool EnableBroadcast { get; set; }//设置允许广播
void Close();//关闭对象相关资源
int Send(byte[] dgram, int bytes, IPEndPoint endPoint);//发送udp数据包,参数(数据,目标ip,目标端口)
int Available { get; }//是否有数据可读
byte[] Receive(ref IPEndPoint remoteEP);//读取数据(阻塞函数),开启一个线程循环调用此函数读取
}
- Udp client
UdpClient {//.net提供的类
UdpClient();//新建对象即可使用,没有Open函数
void Close();//关闭对象相关资源
int Send(byte[] dgram, int bytes, IPEndPoint endPoint);//发送udp数据包,参数(数据,目标ip,目标端口)
int Available { get; }//是否有数据可读
byte[] Receive(ref IPEndPoint remoteEP);//读取数据(阻塞函数),开启一个线程循环调用此函数读取
}
- Udp server
UdpClient {//.net提供的类
UdpClient(int port);//新建对象即可使用,没有Open函数,建立udp服务端需要在构造函数输入“监听端口”
void Close();//关闭对象相关资源
int Send(byte[] dgram, int bytes, IPEndPoint endPoint);//发送udp数据包,参数(数据,目标ip,目标端口)
int Available { get; }//是否有数据可读
byte[] Receive(ref IPEndPoint remoteEP);//读取数据(阻塞函数),开启一个线程循环调用此函数读取
}
- Tcp client
TcpClient {//.net提供的类
void Connect(IPAddress address, int port);//开始向服务端连接,参数:服务器ip,服务器端口
NetworkStream GetStream();获取网络通信流,用这个流来最终完成数据收发
void Close();///关闭相关资源
}
NetworkStream {//.net提供的类
void Write(byte[] buffer, int offset, int size);//写数据
int Read(byte[] buffer, int offset, int size);//收数据
void Close();关闭流
}
- Tcp server
TcpListener {//.net提供的类
TcpListener(IPEndPoint localEP);//参数传入监听端口
void Start();//开始监听
IAsyncResult BeginAcceptTcpClient(AsyncCallback callback, object state);//开始监听客户端的连接请求,在毁掉函数中处理连接请求
TcpClient EndAcceptTcpClient(IAsyncResult asyncResult);//暂停监听客户端请求,并返回一个刚刚建立的通信的TcpClient, 之后使用TcpClient来完成对这个连接的数据收发。
NetworkStream GetStream();//获取网络通信流,用这个流来最终完成数据收发
void Close();//关闭相关资源
}
NetworkStream {//.net提供的类
void Write(byte[] buffer, int offset, int size);//写数据
int Read(byte[] buffer, int offset, int size);//收数据
void Close();//关闭流
}
四、核心编写逻辑代码
- 打开与关闭的逻辑
//经过简化的代码
private void ButtonOpen_Click(object sender, EventArgs e)
{
if (netManager.IsOpen()) //IsOPen
{ //do close
netManager.Close();
}
else
{ //do open
string des_ip = textBoxNetDesIp.Text;
string des_port = textBoxNetDesPort.Text;
//net type
int index = comboBoxNetType.SelectedIndex;
CommNetType.NetType netType = NetManager.GetNetTypeByIndex(index);
int port = int.Parse(des_port);
netManager.Open(netType, des_ip, port);
}
}
- 发送数据逻辑
//经过简化的代码
private void ButtonSend_Click(object sender, EventArgs e)
{
string send_str = textBoxNetSend.Text;
if (checkBoxNetSendHex.Checked)
{
byte[] data = HexFormatUtils.String2HexByte(send_str);
netManager.Send(data);
}
else
{
Encoding encodingGB2312 = Encoding.GetEncoding("gb2312");
Byte[] byte_array = encodingGB2312.GetBytes(send_str.ToCharArray());
netManager.Send(byte_array);
}
}
- 接收数据逻辑
private void OnNetRecvListener(byte[] data, int length, IPEndPoint iped) {
if (checkBoxNetRecvHex.Checked)
{
BeginInvoke(new MethodInvoker(delegate
{
AddRecvMsg(HexFormatUtils.HexByte2String(data));
}));
}
else
{
BeginInvoke(new MethodInvoker(delegate
{
Encoding encodingGB2312 = Encoding.GetEncoding("gb2312");
Char[] c_data = encodingGB2312.GetChars(data);
string str = new String(c_data);
AddRecvMsg(str);
}));
}
}
五、获取源代码
点击此链接获取源代码