读书人

C#Socket异步通信在处置批量并发时有时

发布时间: 2013-12-13 13:57:17 作者: rapoo

C#Socket异步通信在处理批量并发时有时出现数据重叠
代码如下:当并发数量较大时,会出现数据冲突,求改进方案

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Collections.Specialized;
using System.Threading;

namespace SocketServer
{
public partial class frmMain : Form
{
static int count = 0;
static int recvCount = 0;

public frmMain()
{
InitializeComponent();
}

private delegate void ShowMsgHandler(string msg);

IList<Socket> clientList = new List<Socket>();
Dictionary<Socket, System.Threading.Timer> clientArray = new Dictionary<Socket, System.Threading.Timer>();

private void ShowMsg(string msg)
{
if (!txtContent.InvokeRequired)
{
txtContent.Text = msg + Environment.NewLine + txtContent.Text;
}
else
{
ShowMsgHandler handler = new ShowMsgHandler(ShowMsg);
BeginInvoke(handler, new object[] { msg });
}

}

private void btnStartServer_Click(object sender, EventArgs e)
{
IPAddress[] localIPs;
localIPs = Dns.GetHostAddresses(Dns.GetHostName());
StringCollection IpCollection = new StringCollection();
foreach (IPAddress ip in localIPs)
{
if (ip.AddressFamily == AddressFamily.InterNetwork) //如果为IPv4
{
if (Int32.Parse(txtPort.Text.ToString()) != 0)
{
TcpListener listener = new TcpListener(ip, Int32.Parse(txtPort.Text.ToString()));
listener.Start();
listener.BeginAcceptTcpClient(new AsyncCallback(OnAcceptedTcpClient), listener);
}
else
{
TcpListener listener = new TcpListener(ip, 6000);
listener.Start();
listener.BeginAcceptTcpClient(new AsyncCallback(OnAcceptedTcpClient), listener);
}




txtContent.Text = "Start Listiner...";
btnStartServer.Enabled = false;
ShowMsg(ip.ToString());
break;
}
}
}

byte[] buffer = new byte[1024];

public void TimerCallback(object state)
{

Socket sock = (Socket)state;
if (clientArray.Remove(sock))
{
ShowMsg("TimerCallback");
}
sock.Close(100);
}

private void OnAcceptedTcpClient(IAsyncResult ar)
{
if (!ar.IsCompleted)
{
return;
}
TcpListener listener = (TcpListener)ar.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(ar);
System.Threading.Timer time = new System.Threading.Timer(TimerCallback, client.Client, 20000, 10000);
clientArray.Add(client.Client, time);

ShowMsg("连接成功 ");
count++;
listener.BeginAcceptTcpClient(new AsyncCallback(OnAcceptedTcpClient), listener);
{
client.Client.BeginReceive(buffer, 0, 1024, SocketFlags.None, new AsyncCallback(OnReceivedData), client.Client);
}

}

private void OnReceivedData(IAsyncResult ar)
{


if (!ar.IsCompleted)
{
return;
}
Socket s = (Socket)ar.AsyncState;
try
{
int size = s.EndReceive(ar);
if (size > 0)
{
{
string str = System.Text.Encoding.Default.GetString(buffer, 0, size);
ShowMsg(str);
}

recvCount++;


clientArray.Remove(s);
s.Shutdown(SocketShutdown.Both);
s.Close(100);
}
else
{
clientArray.Remove(s);
s.Close(100);

return;
}
// s.BeginReceive(buffer, 0, 1024, SocketFlags.None, new AsyncCallback(OnReceivedData), s);
}
catch (SocketException )
{
clientArray.Remove(s);

s.Close(100);
}

}

private void btnSend_Click(object sender, EventArgs e)
{
byte[] msg = System.Text.Encoding.Unicode.GetBytes(txtMsg.Text.Trim());
foreach (Socket s in clientList)
{
s.BeginSend(msg, 0, msg.Length, SocketFlags.None, new AsyncCallback(OnSendMsg), s);
}
}

private void OnSendMsg(IAsyncResult ar)
{
if(!ar.IsCompleted)
{
return;
}
Socket s = (Socket)ar.AsyncState;
s.EndSend(ar);
}

private void TotleCount_Click(object sender, EventArgs e)
{
ShowMsg("连接数:" + count.ToString() +" 收包数:" + recvCount + " 现连接: " + /*clientList.Count*/clientArray.Count);
}
}
}


[解决办法]
1.服务端accept一个client后 不能使用同一个buffer接收数据
2.数据接收返回后,buffer不一定是完整的数据
[解决办法]
如果前后两个连接数据同时到达 写入缓冲区后 就会覆盖 总有一个连接的EndReceive()不会返回 或者返回了 size也为零
你不要以为客户端按顺序先后登录发送数据 它们到达服务器的顺序就是一定是先后顺序的 所以buffer用同一个没事儿 不一定

读书人网 >C#

热点推荐