我要实现的功能是:一个客户端程序直接服务器建立100-1000个连接,而不是开100-1000个客户端,每个客户端建立一个连接。采用异步编程,然后发送的数据包可以灵活增加和减少。(每个连接发送的数据包相同)实现的界面图如下:1.在点击“发送”按钮后,则开始发起创建100-1000个连接请求。
代码如下:#region 开始准备发送数据包
/// <summary>
/// 开始准备发送数据包
/// 1.禁用相关按钮与容器
/// 2.判断是否开启了连接,如果连接已开启,则继续操作
/// 3.是否选择了要发送的数据包,如果没有,则不发送数据包并提示选择数据包
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSend_Click(object sender, EventArgs e)
{
#region 禁用按钮与容器
btnSend.Enabled = false;
clBoxPacket.Enabled = false;
clBoxChild.Enabled = false;
#endregion TcpClient tcp;
if (isConnected)
{
if (hashTable.Count > 0)
{
txtLog.Text += "(" + DateTime.Now.ToString() + ")开始发送数据包:"; #region 获取要发送的数据包
foreach (DictionaryEntry entry in hashTable)
{
txtLog.Text += entry.Value.ToString().Split(',')[3] + ",";
sPacket += entry.Value + "|";
}
txtLog.Text = txtLog.Text.Substring(0, txtLog.Text.Length - 1) + "\r\n";
#endregion
}
else
{
MessageBox.Show("请选择要发送的数据包");
return;
} #region 创建多个线程 并启动创建连接
for (int i = 0; i <= sckNum / 30; i++)
{
Thread thread = new Thread(new ParameterizedThreadStart(CreateTcp));
thread.Start(i);
}
#endregion }
}
#endregion #region 创建连接并开始连接服务器
/// <summary>
///
/// </summary>
/// <param name="i"></param>
private void CreateTcp(object i)
{
int sNum = sckNum - 30 * Convert.ToInt32(i);
TcpClient tcp;
if (sNum >= 30)
{
for (int j = 0; j < 30; j++)
{
tcp = new TcpClient();
tcp.ConnectedServer += new NetEvent(ClientConn);
tcp.SendDatagram += new NetEvent(SendData);
tcp.ReceivedDatagram += new NetEvent(RecvData);
tcp.Connect(Config.ServerIp, Config.ServerPort);
Thread.Sleep(sckNum);
}
}
else
{
for (int j = 0; j < sNum; j++)
{
tcp = new TcpClient();
tcp.ConnectedServer += new NetEvent(ClientConn);
tcp.SendDatagram += new NetEvent(SendData);
tcp.ReceivedDatagram += new NetEvent(RecvData);
tcp.Connect(Config.ServerIp, Config.ServerPort);
Thread.Sleep(sckNum);
}
}
}
#endregion2.在连接与服务器成功建立连接后,触发相应事件,通知客户端,客户端在接收到事件后,进行以下操作处理
a.记录连接成功日志
b.记录连接列表
c.分析数据包队列,并开始发送第一个数据包
代码如下:///日志信息记录
string strLog = "(Socket" + e.Client.ClientSocket.Handle.ToString() + ")建立连接成功\r\n"; lock (this)
{
File.AppendAllText(logPath + e.Client.ClientSocket.Handle.ToString() + ".log", strLog);
} TcpClient tcpCli = (TcpClient)sender; ///设置Socket连接需要发送的数据包集合
tcpCli.Packet = sPacket; #region 记录Socket列表
SckItems<int, string> sckItem = new SckItems<int, string>();
sckItem.Value = e.Client.ClientSocket.Handle.ToInt32();
sckItem.Text = "Socket" + e.Client.ClientSocket.Handle.ToString();
if (!lbSckList.Items.Contains(sckItem))
{
lbSckList.Items.Add(sckItem);
}
#endregion ///返回数据包集合中的第一个数据包和其余数据包
///result[0]为第一个数据包
///result[1]为其余数据包集合
string[] result = Packet.SplitPacket(tcpCli.Packet);
///设置数据包集合
tcpCli.Packet = result[1];
///说明信息
string msg = string.Empty; #region 发送数据包
byte[] packetByte;
string[] itemArray = result[0].Split(',');
ushort parentType = ushort.Parse(itemArray[0]);
ushort childType = ushort.Parse(itemArray[1]);
int childID = int.Parse(itemArray[2]);
packetByte = Packet.GetPacket(parentType, childType, childID, ref msg);
///包说明信息
msg = itemArray[3] + "|" + msg;
///发送数据包
tcpCli.Send(packetByte, msg);
#endregion3.服务端接收到发送的数据包后,会进行处理,然后返回一个数据包,当客户端接收到返回数据包时,触发处理事件,进行如下操作:
a.分析数据包信息并记录日志
b.分析数据包队列是否发送完毕,如果没有发送完毕,继续发送下一个数据包,否则,关闭连接。
代码如下:#region 记录日志信息
string[] msg = GetRecvPacket(e.Client.Datagram).Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
string strLog = "(Socket" + e.Client.ClientSocket.Handle.ToString() + ")接收到“" + msg[0] + "”反馈数据包,反馈信息:" + msg[1];
strLog = strLog.Substring(0, strLog.Length - 1) + "\r\n"; lock (this)
{
File.AppendAllText(logPath + e.Client.ClientSocket.Handle.ToString() + ".log", strLog);
}
#endregion TcpClient tcpCli = (TcpClient)sender; #region 如果数据包尚未发送完毕,继续发送
if (tcpCli.Packet != null)
{
string[] result = Packet.SplitPacket(tcpCli.Packet);
///设置数据包集合
tcpCli.Packet = result[1];
///说明信息
string infor = string.Empty; #region 发送数据包
byte[] packetByte;
string[] itemArray = result[0].Split(',');
ushort parentType = ushort.Parse(itemArray[0]);
ushort childType = ushort.Parse(itemArray[1]);
int childID = int.Parse(itemArray[2]);
packetByte = Packet.GetPacket(parentType, childType, childID, ref infor);
infor = itemArray[3] + "|" + infor;
tcpCli.Send(packetByte, infor);
#endregion
}
else
{
#region 当前连接数据包已全部发送完毕
lock (this)
{
///记录已发送数据包
sendPacketNum++;
///显示已发送数据包
lblSendNum.Text = "已经发送数据包的数量:" + sendPacketNum.ToString();
///设置进度条
progressBar1.Value = (sendPacketNum * 100) / sckNum;
} lock (this)
{
///添加日志信息
File.AppendAllText(logPath + e.Client.ClientSocket.Handle.ToString() + ".log", "(Socket" + e.Client.ClientSocket.Handle.ToString() + ")断开连接成功\r\n\r\n");
}
///关闭连接等待重用
tcpCli.Close();
#endregion
}
#endregion主要实现思路都在上面了,由于涉及到灵活增加和减少要发送的数据包,所以所有数据包信息都存储在数据库中,统一从数据库中读取数据包信息然后拼接。这属于共享数据,因此使用了lock锁,会对性能有影响,但是我不知道如何处理比较好?请各位高手,专家多多指点。
代码如下:#region 开始准备发送数据包
/// <summary>
/// 开始准备发送数据包
/// 1.禁用相关按钮与容器
/// 2.判断是否开启了连接,如果连接已开启,则继续操作
/// 3.是否选择了要发送的数据包,如果没有,则不发送数据包并提示选择数据包
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSend_Click(object sender, EventArgs e)
{
#region 禁用按钮与容器
btnSend.Enabled = false;
clBoxPacket.Enabled = false;
clBoxChild.Enabled = false;
#endregion TcpClient tcp;
if (isConnected)
{
if (hashTable.Count > 0)
{
txtLog.Text += "(" + DateTime.Now.ToString() + ")开始发送数据包:"; #region 获取要发送的数据包
foreach (DictionaryEntry entry in hashTable)
{
txtLog.Text += entry.Value.ToString().Split(',')[3] + ",";
sPacket += entry.Value + "|";
}
txtLog.Text = txtLog.Text.Substring(0, txtLog.Text.Length - 1) + "\r\n";
#endregion
}
else
{
MessageBox.Show("请选择要发送的数据包");
return;
} #region 创建多个线程 并启动创建连接
for (int i = 0; i <= sckNum / 30; i++)
{
Thread thread = new Thread(new ParameterizedThreadStart(CreateTcp));
thread.Start(i);
}
#endregion }
}
#endregion #region 创建连接并开始连接服务器
/// <summary>
///
/// </summary>
/// <param name="i"></param>
private void CreateTcp(object i)
{
int sNum = sckNum - 30 * Convert.ToInt32(i);
TcpClient tcp;
if (sNum >= 30)
{
for (int j = 0; j < 30; j++)
{
tcp = new TcpClient();
tcp.ConnectedServer += new NetEvent(ClientConn);
tcp.SendDatagram += new NetEvent(SendData);
tcp.ReceivedDatagram += new NetEvent(RecvData);
tcp.Connect(Config.ServerIp, Config.ServerPort);
Thread.Sleep(sckNum);
}
}
else
{
for (int j = 0; j < sNum; j++)
{
tcp = new TcpClient();
tcp.ConnectedServer += new NetEvent(ClientConn);
tcp.SendDatagram += new NetEvent(SendData);
tcp.ReceivedDatagram += new NetEvent(RecvData);
tcp.Connect(Config.ServerIp, Config.ServerPort);
Thread.Sleep(sckNum);
}
}
}
#endregion2.在连接与服务器成功建立连接后,触发相应事件,通知客户端,客户端在接收到事件后,进行以下操作处理
a.记录连接成功日志
b.记录连接列表
c.分析数据包队列,并开始发送第一个数据包
代码如下:///日志信息记录
string strLog = "(Socket" + e.Client.ClientSocket.Handle.ToString() + ")建立连接成功\r\n"; lock (this)
{
File.AppendAllText(logPath + e.Client.ClientSocket.Handle.ToString() + ".log", strLog);
} TcpClient tcpCli = (TcpClient)sender; ///设置Socket连接需要发送的数据包集合
tcpCli.Packet = sPacket; #region 记录Socket列表
SckItems<int, string> sckItem = new SckItems<int, string>();
sckItem.Value = e.Client.ClientSocket.Handle.ToInt32();
sckItem.Text = "Socket" + e.Client.ClientSocket.Handle.ToString();
if (!lbSckList.Items.Contains(sckItem))
{
lbSckList.Items.Add(sckItem);
}
#endregion ///返回数据包集合中的第一个数据包和其余数据包
///result[0]为第一个数据包
///result[1]为其余数据包集合
string[] result = Packet.SplitPacket(tcpCli.Packet);
///设置数据包集合
tcpCli.Packet = result[1];
///说明信息
string msg = string.Empty; #region 发送数据包
byte[] packetByte;
string[] itemArray = result[0].Split(',');
ushort parentType = ushort.Parse(itemArray[0]);
ushort childType = ushort.Parse(itemArray[1]);
int childID = int.Parse(itemArray[2]);
packetByte = Packet.GetPacket(parentType, childType, childID, ref msg);
///包说明信息
msg = itemArray[3] + "|" + msg;
///发送数据包
tcpCli.Send(packetByte, msg);
#endregion3.服务端接收到发送的数据包后,会进行处理,然后返回一个数据包,当客户端接收到返回数据包时,触发处理事件,进行如下操作:
a.分析数据包信息并记录日志
b.分析数据包队列是否发送完毕,如果没有发送完毕,继续发送下一个数据包,否则,关闭连接。
代码如下:#region 记录日志信息
string[] msg = GetRecvPacket(e.Client.Datagram).Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
string strLog = "(Socket" + e.Client.ClientSocket.Handle.ToString() + ")接收到“" + msg[0] + "”反馈数据包,反馈信息:" + msg[1];
strLog = strLog.Substring(0, strLog.Length - 1) + "\r\n"; lock (this)
{
File.AppendAllText(logPath + e.Client.ClientSocket.Handle.ToString() + ".log", strLog);
}
#endregion TcpClient tcpCli = (TcpClient)sender; #region 如果数据包尚未发送完毕,继续发送
if (tcpCli.Packet != null)
{
string[] result = Packet.SplitPacket(tcpCli.Packet);
///设置数据包集合
tcpCli.Packet = result[1];
///说明信息
string infor = string.Empty; #region 发送数据包
byte[] packetByte;
string[] itemArray = result[0].Split(',');
ushort parentType = ushort.Parse(itemArray[0]);
ushort childType = ushort.Parse(itemArray[1]);
int childID = int.Parse(itemArray[2]);
packetByte = Packet.GetPacket(parentType, childType, childID, ref infor);
infor = itemArray[3] + "|" + infor;
tcpCli.Send(packetByte, infor);
#endregion
}
else
{
#region 当前连接数据包已全部发送完毕
lock (this)
{
///记录已发送数据包
sendPacketNum++;
///显示已发送数据包
lblSendNum.Text = "已经发送数据包的数量:" + sendPacketNum.ToString();
///设置进度条
progressBar1.Value = (sendPacketNum * 100) / sckNum;
} lock (this)
{
///添加日志信息
File.AppendAllText(logPath + e.Client.ClientSocket.Handle.ToString() + ".log", "(Socket" + e.Client.ClientSocket.Handle.ToString() + ")断开连接成功\r\n\r\n");
}
///关闭连接等待重用
tcpCli.Close();
#endregion
}
#endregion主要实现思路都在上面了,由于涉及到灵活增加和减少要发送的数据包,所以所有数据包信息都存储在数据库中,统一从数据库中读取数据包信息然后拼接。这属于共享数据,因此使用了lock锁,会对性能有影响,但是我不知道如何处理比较好?请各位高手,专家多多指点。
解决方案 »
- 如何使用wmi来实现远程对服务器上文件夹和文件的操作
- ACCESS获取刚添加数据的ID,总是得到上一条记录的ID??
- 今天理顺了下网站、bs和cs的关系
- 如何在客户端获得自己在一个域的所有cookie?
- 樹控件的綁定
- 关于Dotfuscator Community Edition的注册问题
- 关于textbox的刷新
- 请教!winform如何传数据给网页?
- Visual C#.NET 应用编程150例 随书的代码说是从网站上下载。
- c# 正则表达式去标签中的值
- 关于WPF中的按钮的问题
- asp.net ajax控件,为何在我机器上运行良好,上传服务器后,我在浏览器端运行,报缺少对象错误!如何解决?
你所谓的100-1000个连接,而不是客户端,其实对于tcp而言就是客户端.为什么不分布在多个机器上,并行处理.1000个连接服务器会很累的.