private void RecMsg(object sokConnectionparn)
{
Socket sokClient = sokConnectionparn as Socket;
while (true)
{
byte[] arrMsgRec = new byte[1024 * 1024 * 3+3];
// 将接受到的数据存入到输入 arrMsgRec中;
int length = -1;
try
{
length = sokClient.Receive(arrMsgRec); // 接收数据,并返回数据的长度;
}
catch (SocketException se)
{
ShowMsg("异常:" + se.Message);
dictSocket.Remove(sokClient.RemoteEndPoint.ToString());
dictThread.Remove(sokClient.RemoteEndPoint.ToString());
DeleteLib(sokClient.RemoteEndPoint.ToString());
break;
}
catch (Exception e)
{
ShowMsg("异常:" + e.Message);
dictSocket.Remove(sokClient.RemoteEndPoint.ToString());
dictThread.Remove(sokClient.RemoteEndPoint.ToString());
DeleteLib(sokClient.RemoteEndPoint.ToString());
break;
}
try
{
if (arrMsgRec[0] == 0) // 表示接收到的是数据;
{
string strMsg = System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length - 1);// 将接受到的字节数据转化成字符串;
ShowMsg(strMsg);
}
if (arrMsgRec[0] == 1) // 表示接收到的是文件;
{
filesource = sokClient.RemoteEndPoint.ToString();
//var i = BitConverter.ToInt32(arrMsgRec, arrMsgRec.Length-3);
if (System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length - 1).Contains("FileName"))
{
string strMsg = System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length - 1);
bpp.FileName = strMsg.Split(':')[1];
bpp.Index = 0;
savepath = "";
savepath = Path.Combine(savepath, bpp.FileName);
}
else if (System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length - 1).Contains("PackageCount"))
{
string strMsg = System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length - 1);
bpp.PackageCount = int.Parse(strMsg.Split(':')[1]);
}
else if (arrMsgRec[1] == 22 && arrMsgRec[2] == 33)
{
//int i = BitConverter.ToInt32(arrMsgRec, arrMsgRec.Length - 3);
byte[] buffer = new byte[length - 3];
Buffer.BlockCopy(arrMsgRec, 3, buffer, 0, buffer.Length);
if (!string.IsNullOrEmpty(bpp.FileName))
{
Thread fw = new Thread(() => FileWrite(savepath, bpp.Index, 1024 * 1024 * 3, buffer.Length, buffer));
fw.IsBackground = true;
fw.Start();
}
}
else
{
stringtobyte("Err:" + bpp.Index.ToString(), 1);
dictSocket[filesource].Send(stringtobyte("Err:" + bpp.Index.ToString(), 1));
}
}
}
catch(Exception ex)
{
//MessageBox.Show(ex.Message);
}
}
}
用这个作为后台线程接收,然后发文件(客户端线程分包自动发的)的同时传输信息的话会粘包吧,好像是这个说法,就是那一包文件数据会收不到,然后聊天信息会出现乱码,求教怎么解决,新手实在搞不定- -谢谢.
当socket接收到数据后,会根据buffer的大小一点一点的接收数据,比如:
对方发来了1M的数据量过来,但是,本地的buffer只有1024字节,那就代表socket需要重复很多次才能真正收完这逻辑上的一整个消息。
对方发来了5条2个字符的消息,本地的buffer(大小1024字节)会将这5条消息全部收入囊下...
那么,如何处理呢?下面我以最简单的一种文本消息来demo
根据上面所描述的情况,最重要的关键落在了下面3个因素的处理上
消息的结尾标记
接收消息时判断结尾标记
当本次buffer中没有结尾标记时怎么处理
我把写好的核心算法贴出来:
StringBuilder sb = new StringBuilder(); //这个是用来保存:接收到了的,但是还没有结束的消息
public void ReceiveMessage(object state) //这个函数会被以线程方式运行
{
Socket socket = (Socket)state;
while(true)
{
byte[] buffer = new byte[receiveBufferSize]; //buffer大小,此处为1024
int receivedSize=socket.Receive(buffer);
string rawMsg=System.Text.Encoding.Default.GetString(buffer, 0, receivedSize);
int rnFixLength = terminateString.Length; //这个是指消息结束符的长度,此处为\r\n
for(int i=0;i<rawMsg.Length;) //遍历接收到的整个buffer文本
{
if (i <= rawMsg.Length - rnFixLength)
{
if (rawMsg.Substring(i, rnFixLength) != terminateString)//非消息结束符,则加入sb
{
sb.Append(rawMsg[i]);
i++;
}
else
{
this.OnNewMessageReceived(sb.ToString());//找到了消息结束符,触发消息接收完成事件
sb.Clear();
i += rnFixLength;
}
}
else
{
sb.Append(rawMsg[i]);
i++;
}
}
}
}
A2DTcpClient client = new A2DTcpClient("127.0.0.1", 5000);
client.NewMessageReceived += new MessageReceived(client_NewMessageReceived);
client.Connect();
client.Send("HELLO");
client.Close();
static void client_NewMessageReceived(string msg)
{
Console.WriteLine(msg);
}