定义了一个SocketHelper类,将主要实现进行封装
public class SocketHelper
{
//服务端
private Socket ServerSocket = null;
//tcp客户端字典
public Dictionary<string, Session> dic_ClientSocket = new Dictionary<string, Session>();
//线程字典,每新增一个连接就添加一条线程
private Dictionary<string, Thread> dic_ClientThread = new Dictionary<string, Thread>();
//监听客户端连接的标志
private bool Flag_Listen = true;
//定义的委托将新增的Socket连接传给主窗体的ListView
public delegate void ClientSocketChanged(int status, Session sesson);
public event ClientSocketChanged OnClientSocketChanged;
//定义委托将客户端传过来的消息在主界面上展示出来你
public delegate void SocketText(Session sesson,string text);
public event SocketText getSocketText;
/// <summary>
/// 启动服务
/// </summary>
/// <param name="port">端口号</param>
public bool OpenServer(int port)
{
try
{
Flag_Listen = true;
// 创建负责监听的套接字,注意其中的参数;
ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 创建包含ip和端口号的网络节点对象;
IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, port);
try
{
// 将负责监听的套接字绑定到唯一的ip和端口上;
ServerSocket.Bind(endPoint);
}
catch
{
return false;
}
// 设置监听队列的长度;
ServerSocket.Listen(100);
// 创建负责监听的线程;
Thread Thread_ServerListen = new Thread(ListenConnecting);
Thread_ServerListen.IsBackground = true;
Thread_ServerListen.Start();
return true;
}
catch
{
return false;
}
}
/// <summary>
/// 关闭服务
/// </summary>
public void CloseServer()
{
lock (dic_ClientSocket)
{
foreach (var item in dic_ClientSocket)
{
item.Value.Close();//关闭每一个连接
}
}
lock (dic_ClientThread)
{
foreach (var item in dic_ClientThread)
{
item.Value.Abort();//停止线程
}
dic_ClientThread.Clear();
}
Flag_Listen = false;
//ServerSocket.Shutdown(SocketShutdown.Both);//服务端不能主动关闭连接,需要把监听到的连接逐个关闭
if (ServerSocket != null)
ServerSocket.Close();
}
/// <summary>
/// 监听客户端请求的方法;
/// </summary>
private void ListenConnecting()
{
while (Flag_Listen) // 持续不断的监听客户端的连接请求;
{
try
{
// 一旦监听到一个客户端的请求,就返回一个与该客户端通信的 套接字;
Socket sokConnection = ServerSocket.Accept();
// 将与客户端连接的 套接字 对象添加到集合中;
string str_EndPoint = sokConnection.RemoteEndPoint.ToString();
Session myTcpClient = new Session() { TcpSocket = sokConnection };
//创建线程接收数据
Thread th_ReceiveData = new Thread(ReceiveData);
th_ReceiveData.IsBackground = true;
th_ReceiveData.Start(myTcpClient);
//把线程及客户连接加入字典
dic_ClientThread.Add(str_EndPoint, th_ReceiveData);
dic_ClientSocket.Add(str_EndPoint, myTcpClient);
OnClientSocketChanged(1, myTcpClient);
}
catch
{
}
Thread.Sleep(200);
}
}
/// <summary>
/// 接收数据
/// </summary>
/// <param name="sokConnectionparn"></param>
private void ReceiveData(object sokConnectionparn)
{
Session tcpClient = sokConnectionparn as Session;
Socket socketClient = tcpClient.TcpSocket;
bool Flag_Receive = true;
while (Flag_Receive)
{
try
{
// 定义一个2M的缓存区;
byte[] arrMsgRec = new byte[1024 * 1024 * 2];
// 将接受到的数据存入到输入 arrMsgRec中;
int length = -1;
try
{
length = socketClient.Receive(arrMsgRec); // 接收数据,并返回数据的长度;
}
catch
{
Flag_Receive = false;
// 从通信线程集合中删除被中断连接的通信线程对象;
string keystr = socketClient.RemoteEndPoint.ToString();
dic_ClientThread[keystr].Abort();//关闭线程
dic_ClientThread.Remove(keystr);//删除字典中该线程
tcpClient = null;
socketClient = null;
break;
}
byte[] buf = new byte[length];
Array.Copy(arrMsgRec, buf, length);
lock (tcpClient.m_Buffer)
{
if (!string.IsNullOrEmpty(System.Text.Encoding.Default.GetString(buf)))
{
string text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ">>" + System.Text.Encoding.Default.GetString(buf);
getSocketText(tcpClient,text);
//业务需要,收到客户端的消息后,回复(P35)进行确认
tcpClient.Send(System.Text.Encoding.Default.GetBytes("(P35)"));
Log.Instance.Info(tcpClient.GetIp(), text);
}
}
}
catch
{
}
Thread.Sleep(100);
}
}
/// <summary>
/// 发送数据给指定的客户端
/// </summary>
/// <param name="_endPoint">客户端套接字</param>
/// <param name="_buf">发送的数组</param>
/// <returns></returns>
public bool SendData(string _endPoint, byte[] _buf)
{
Session myT = new Session();
if (dic_ClientSocket.TryGetValue(_endPoint, out myT))
{
myT.Send(_buf);
return true;
}
else
{
return false;
}
}
}
另外每个链接就是一个对象,所以将连接的一些属性定义成了一个Session
public class Session
{
public Socket TcpSocket;//socket对象
public List<byte> m_Buffer = new List<byte>();//数据缓存区
public Session()
{
}
/// <summary>
/// 发送数据
/// </summary>
/// <param name="buf"></param>
public void Send(byte[] buf)
{
if (buf != null)
{
TcpSocket.Send(buf);
}
}
/// <summary>
/// 获取连接的ip
/// </summary>
/// <returns></returns>
public string GetIp()
{
IPEndPoint clientipe = (IPEndPoint)TcpSocket.RemoteEndPoint;
string _ip = clientipe.Address.ToString();
return _ip;
}
/// <summary>
/// 关闭连接
/// </summary>
public void Close()
{
TcpSocket.Shutdown(SocketShutdown.Both);
}
/// <summary>
/// 提取正确数据包
/// </summary>
public byte[] GetBuffer(int startIndex, int size)
{
byte[] buf = new byte[size];
m_Buffer.CopyTo(startIndex, buf, 0, size);
m_Buffer.RemoveRange(0, startIndex + size);
return buf;
}
}
绘制一个主界面,包含启动/关闭按钮,给客户端回复消息操作
主窗体代码
public partial class Form1 : Form
{
SocketHelper socket = new SocketHelper();
public Form1()
{
InitializeComponent();
}
BindingList<RowDataModel> rowList = new BindingList<RowDataModel>();
private void Form1_Load(object sender, EventArgs e)
{
txt_Port.Text = "8888";
listView1.View = View.Details;
listView1.Columns.Add("IP地址", 280);
//设置自动换行
this.dataGridView1.DefaultCellStyle.WrapMode = DataGridViewTriState.True;
//设置自动调整高度
this.dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
dataGridView1.DataSource = rowList;
}
private void btn_Start_Click(object sender, EventArgs e)
{
if (btn_Start.Text == "Start")
{
//启动Socket
if (socket.OpenServer(int.Parse(txt_Port.Text.Trim())))
{
lab_Status.Text = "Server Status:succeed";
lab_Status.ForeColor = Color.Green;
}
else
{
lab_Status.Text = "Server Status:fail";
lab_Status.ForeColor = Color.Red;
}
socket.OnClientSocketChanged += Socket_OnClientSocketChanged;
socket.getSocketText += Socket_getSocketText;
btn_Start.Text = "Stop";
}
else
{
socket.CloseServer();
socket.OnClientSocketChanged -= Socket_OnClientSocketChanged;
socket.getSocketText -= Socket_getSocketText;
btn_Start.Text = "Start";
lab_Status.Text = "Server Status:";
lab_Status.ForeColor = Color.Black;
}
}
private void Socket_OnClientSocketChanged(int status, Session sesson)
{
if (status == 1)
{
ListViewItem item = new ListViewItem();
item.Text = sesson.GetIp();
item.Tag = sesson;
listView1.Items.Add(item);
}
else if (status == 0)
{
ListViewItem item = new ListViewItem();
item.Text = sesson.GetIp();
item.Tag = sesson;
listView1.Items.Remove(item);
}
else
{
listView1.Items.Clear();
}
}
private void listView1_MouseDoubleClick(object sender, MouseEventArgs e)
{
dataGridView1.Rows.Clear();
ListViewHitTestInfo info = listView1.HitTest(e.X, e.Y);
if (info.Item != null)
{
string path = AppDomain.CurrentDomain.BaseDirectory + "Log\\" + "Info\\Log_Info_" + listView1.SelectedItems[0].Text + ".txt";
Read(path);
}
}
private void Socket_getSocketText(Session sesson,string text)
{
listView1.SelectedItems[0].BackColor = Color.Yellow;
if (socket.dic_ClientSocket.Count == 1)
{
RowDataModel model = new RowDataModel();
model.rowdata = text;
model.length = text.Length;
rowList.Add(model);
}
else
{
if (sesson.GetIp().Equals(listView1.SelectedItems[0].Text))
{
RowDataModel model = new RowDataModel();
model.rowdata = text;
model.length = text.Length;
rowList.Add(model);
}
}
}
private void Read(string path)
{
StreamReader sr = new StreamReader(path, Encoding.Default);
String line;
while ((line = sr.ReadLine()) != null)
{
RowDataModel model = new RowDataModel();
model.rowdata = line.ToString();
model.length = line.ToString().Length;
rowList.Add(model);
}
}
private void btn_Send_Click(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(txt_Data.Text.Trim()))
{
Session sesson = (Session)listView1.SelectedItems[0].Tag;
sesson.Send(System.Text.Encoding.Default.GetBytes(txt_Data.Text.Trim()));
}
else
{
MessageBox.Show("发送数据不能为空", "提示");
}
}
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
string selectText = dataGridView1.CurrentCell.Value.ToString();
//传过来的数据是JSON格式,则将数据格式化,方便数据验证
richTextBox2.Text = selectText.Split(new string[] { ">>" }, StringSplitOptions.None)[1].Replace(",",",\r\n").Replace("{", "{\r\n");
}
}
结束!继续划水…