本案例使用前面封装的网络服务类编写简易聊天室,采用Tcp和多线程相关技术:
![.Net网络通讯编程[利用Socket实现字串、文件、序列化对象传输]--使用封装的网络服务3[聊天室] .Net网络通讯编程[利用Socket实现字串、文件、序列化对象传输]--使用封装的网络服务3[聊天室]](/default/index/img?u=L2RlZmF1bHQvaW5kZXgvaW1nP3U9YUhSMGNITTZMeTlwYldGblpYTXVZMjVpYkc5bmN5NWpiMjB2WTI1aWJHOW5jMTlqYjIwdmFtbGhibWQwYjI1bkx6SXdNVEl3TXk4eU1ERXlNRE15T0RBNU5UQTBNekl6TXprdWNHNW4=)
App.config文件:
![]()
ServerName"
value="
127.0.0.1"/>
<!--本地端口-->
<add key="
ServerPort"
value="
6000"/>
<!--远程服务器名-->
<add key="
RemoteServerName"
value="
127.0.0.1"/>
<!--远程服务器端口-->
<add key="
RemoteServerPort"
value="
6000"/>
</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>
/// Tcp服务对象[提供发包和收包功能],接收消息和文件使用
///
</summary>
NetPacketService tcpPacketServiceSvr = null;
///
<summary>
/// Tcp服务对象[提供发包和收包功能],发送消息和文件使用
///
</summary>
NetPacketService tcpPacketServiceClient = null;
///
<summary>
/// 客户端Socket[发送消息和文件]
///
</summary>
Socket clientSocket = null;
public string ServerName
{
get
{
return ConfigurationManager.AppSettings["ServerName"];
}
}
public Int32 ServerPort
{
get
{
return Convert.ToInt32(ConfigurationManager.AppSettings["ServerPort"]);
}
}
public String RemoteServerName
{
get
{
return ConfigurationManager.AppSettings["RemoteServerName"];
}
}
public Int32 RemoteServerPort
{
get
{
return Convert.ToInt32(ConfigurationManager.AppSettings["RemoteServerPort"]);
}
}
public FrmChat()
{
InitializeComponent();
}
private void FrmChat_Load(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(ReceiveMessage));
thread.IsBackground = true;//设置当前线程为后台线程,以使当主窗体被关闭后自动结束线程
thread.Start();
}
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);//开始监听
Socket ctSocket = serverSocket.Accept();//接收一个请求
NetworkStream netStream = new NetworkStream(ctSocket);
tcpPacketServiceSvr = new NetPacketTcpService(netStream);
while(true)
{
//在窗口界面所在的线程运行委托指向的方法,避免跨线程访问UI问题
Invoke(new UpdateViewHandler(UpdateView), tcpPacketServiceSvr.ReceivePacket());
}
}
///
<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 NetPacketTcpService(netStream);
}
tcpPacketServiceClient.SendText(txtMsg.Text.Trim());
String msglist = txtMsgList.Text;
msglist += "\r\n我说:" + txtMsg.Text.Trim();
txtMsgList.Text = msglist;
}
///
<summary>
/// 发送文件
///
</summary>
///
<param name=
"sender"></param>
///
<param name=
"e"></param>
private void btnSendFile_Click(object sender, EventArgs e)
{
OpenFileDialog fd = new OpenFileDialog();
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 NetPacketTcpService(netStream);
}
//在新的线程中完成文件发送
Thread thread = new Thread(delegate() //采用C#2.0匿名方法语法
{
tcpPacketServiceClient.SendFile(fd.FileName);
//在窗口界面所在的线程运行委托指向的方法,避免跨线程访问UI问题
Invoke(new UpdateViewWithMsgHandler(UpdateView), "我发送了文件:" + new FileInfo(fd.FileName).Name);
});
thread.IsBackground = true;
thread.Start();
}
}
}
使用方式:请将编译后的debug目录拷贝两份,分别配置不同的端口即可,比如a目录的配置端口为本地6001,远程6002,b目录的配置端口为本地6002,远程6001,这样即可在同一台机器实现通信。