.Net网络通讯编程[利用Socket实现字串、文件、序列化对象传输]
本案例使用前面封装的网络服务类编写简易聊天室,采用Tcp和异步套接字相关技术:
App.config文件:
示范代码<??><configuration> <appSettings> <!--本地服务器名--> <add key="ServerName" value="127.0.0.1"/> <!--本地端口--> <add key="ServerPort" value="6001"/> <!--远程服务器名--> <add key="RemoteServerName" value="127.0.0.1"/> <!--远程服务器端口--> <add key="RemoteServerPort" value="6002"/> </appSettings></configuration>
聊天窗体完整代码:
示范代码using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using TcpLabCommon;using System.Net.Sockets;using System.Net;using System.Configuration;using System.Threading;using System.IO;namespace TcpLabChat1{ public partial class FrmChat : Form { delegate void UpdateViewHandler(NetPacket packet); delegate void UpdateViewWithMsgHandler(string msg); /// <summary> /// 文件对话框 /// </summary> OpenFileDialog fd = new OpenFileDialog(); /// <summary> /// Tcp服务对象[提供发包和收包功能],接收消息和文件使用 /// </summary> NetPacketService tcpPacketServiceSvr = null; /// <summary> /// Tcp服务对象[提供发包和收包功能],发送消息和文件使用 /// </summary> NetPacketService tcpPacketServiceClient = null; /// <summary> /// 客户端Socket[发送消息和文件] /// </summary> Socket clientSocket = null; /// <summary> /// 本地服务器名 /// </summary> public string ServerName { get { return ConfigurationManager.AppSettings["ServerName"]; } } /// <summary> /// 本地监听端口 /// </summary> public Int32 ServerPort { get { return Convert.ToInt32(ConfigurationManager.AppSettings["ServerPort"]); } } /// <summary> /// 对方服务器名 /// </summary> public String RemoteServerName { get { return ConfigurationManager.AppSettings["RemoteServerName"]; } } /// <summary> /// 对方服务器监听端口 /// </summary> public Int32 RemoteServerPort { get { return Convert.ToInt32(ConfigurationManager.AppSettings["RemoteServerPort"]); } } public FrmChat() { InitializeComponent(); } private void FrmChat_Load(object sender, EventArgs e) { ReceiveMessage(); } /// <summary> /// 异步接收对方发来的消息 /// </summary> private void ReceiveMessage() { Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); EndPoint endPoint = new IPEndPoint(IPAddress.Parse(ServerName), ServerPort);//创建一个终结点 serverSocket.Bind(endPoint);//绑定终结点 serverSocket.Listen(0);//开始监听 serverSocket.BeginAccept(new AsyncCallback(AsyncCallbackAccept),serverSocket);//接收一个请求 } private void AsyncCallbackAccept(IAsyncResult result) { Socket serverSocket = (Socket)result.AsyncState; Socket ctSocket = serverSocket.EndAccept(result); NetworkStream netStream = new NetworkStream(ctSocket); tcpPacketServiceSvr = new NetPacketTcpAsynService(netStream); (tcpPacketServiceSvr as NetPacketTcpAsynService).OnReceivedPacket += new TcpAsynHandler1(FrmChat_OnReceivedPacket); tcpPacketServiceSvr.ReceivePacket(); } void FrmChat_OnReceivedPacket(NetPacket packet) { //在窗口界面所在的线程运行委托指向的方法,避免跨线程访问UI问题 Invoke(new UpdateViewHandler(UpdateView), packet); } /// <summary> /// 更新界面 /// </summary> /// <param name="packet"></param> private void UpdateView(NetPacket packet) { String msglist = txtMsgList.Text; switch (packet.PacketHead.PType) { case PacketType.STRING: msglist += "\r\n对方说:"+packet.Data.ToString(); break; case PacketType.BINARY: NetFile f = tcpPacketServiceSvr.ParseFile((Byte[])packet.Data); msglist += "\r\n接收了对方发送的文件:"+f.FileName; FileStream fs = null; try { string fname = Application.StartupPath+"\\"+f.FileName; fs = new FileStream(fname, FileMode.Create); fs.Write(f.Content, 0, f.Content.Length); fs.Flush(); } catch (Exception e) { MessageBox.Show(e.Message); } finally { fs.Close(); } break; case PacketType.COMPLEX: break; default: break; } txtMsgList.Text = msglist; } private void UpdateView(string msg) { String msglist = txtMsgList.Text; msglist += "\r\n"+msg; txtMsgList.Text = msglist; } /// <summary> /// 发送消息 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnSendMsg_Click(object sender, EventArgs e) { if (txtMsg.Text.Trim().Length == 0) return; if (clientSocket == null) { clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); clientSocket.Connect(IPAddress.Parse(RemoteServerName), RemoteServerPort); NetworkStream netStream = new NetworkStream(clientSocket); tcpPacketServiceClient = new NetPacketTcpAsynService(netStream); } //注册事件,当发送成功后执行的函数[注意该事件只注册一次] //取消订阅事件 (tcpPacketServiceClient as NetPacketTcpAsynService).OnAfterSendPacket -= new TcpAsynHandler2(FrmChat_OnAfterSendPacket); //再次订阅事件 (tcpPacketServiceClient as NetPacketTcpAsynService).OnAfterSendPacket += new TcpAsynHandler2(FrmChat_OnAfterSendPacket); //发包 tcpPacketServiceClient.SendText(txtMsg.Text.Trim()); } /// <summary> /// 当发送成功后执行的函数 /// </summary> /// <param name="msg"></param> void FrmChat_OnAfterSendPacket(NetPacketHead packetHead) { switch (packetHead.PType) { case PacketType.STRING: String msglist = txtMsgList.Text; msglist += "\r\n我说:" + txtMsg.Text.Trim(); txtMsgList.Text = msglist; break; case PacketType.BINARY: //在窗口界面所在的线程运行委托指向的方法,避免跨线程访问UI问题 Invoke(new UpdateViewWithMsgHandler(UpdateView), "我发送了文件:" + new FileInfo(fd.FileName).Name); break; case PacketType.COMPLEX: break; default: break; } } /// <summary> /// 发送文件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnSendFile_Click(object sender, EventArgs e) { if (fd.ShowDialog() == System.Windows.Forms.DialogResult.Cancel) { return; } if (clientSocket == null) { clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); clientSocket.Connect(IPAddress.Parse(RemoteServerName), RemoteServerPort); NetworkStream netStream = new NetworkStream(clientSocket); tcpPacketServiceClient = new NetPacketTcpAsynService(netStream); } //注册事件,当发送成功后执行的函数[注意该事件只注册一次] //取消订阅事件 (tcpPacketServiceClient as NetPacketTcpAsynService).OnAfterSendPacket -= new TcpAsynHandler2(FrmChat_OnAfterSendPacket); //再次订阅事件 (tcpPacketServiceClient as NetPacketTcpAsynService).OnAfterSendPacket += new TcpAsynHandler2(FrmChat_OnAfterSendPacket); tcpPacketServiceClient.SendFile(fd.FileName); } }}
TAG:C# Tcp Udp 粘包