/// <summary> /// 准备关闭与对方的Socket连接,关闭之前通知对方 /// </summary> public void CloseSocket() { // 通知对方关闭Socket连接 try { ProtocalHandler protocalHandler = new ProtocalHandler(main.MyName); string protocalText = protocalHandler.Pack("ctl_closesocket"); byte[] sendbuf = Encoding.ASCII.GetBytes(protocalText); SocketAsyncEventArgs saEA = new SocketAsyncEventArgs(); saEA.Completed += new EventHandler <SocketAsyncEventArgs>( closeSocketCompletedEventHandler); saEA.SetBuffer(sendbuf, 0, sendbuf.Length); socket.SendAsync(saEA); } catch // 异常则已经关闭 { socket = null; } try { owner.removeClientDelegate(targetName); } catch (Exception ex) { Trace.WriteLine("异常位置:P2PGroupClient.closeSocket"); Trace.WriteLine(ex.Message); } }
/// <summary> /// 发起方: /// 成功建立Socket连接,准备发送1次确认 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void createSocketCompletedEventHandler( object sender, EventArgs ea) { // 取得新建的Socket(如果连接成功) // 此Socket应等于this.socket SocketAsyncEventArgs socketAsyncEA = (SocketAsyncEventArgs)ea; Socket createdSocket = socketAsyncEA.ConnectSocket; if (createdSocket != null && createdSocket == socket) // 连接成功 { // 1次确认,发送name=自己(发起方)用户名 ProtocalHandler protocalHandler = new ProtocalHandler(main.MyName); string protocalText = protocalHandler.Pack("init_gp_request"); // 发送群中所有好友 foreach (string friend in owner.friends) { string friendBase64 = protocalHandler.StringToBase64string(friend); protocalText = protocalHandler.Append( protocalText, "target", friendBase64); } byte[] sendbuf = Encoding.ASCII.GetBytes(protocalText); SocketAsyncEventArgs saEA = new SocketAsyncEventArgs(); saEA.Completed += new EventHandler <SocketAsyncEventArgs>( createdSocketSendNamesCompletedEventHandler); saEA.SetBuffer(sendbuf, 0, sendbuf.Length); socket.SendAsync(saEA); } }
/// <summary> /// 中途主动取消文件收发 /// </summary> public void StopToSendFile() { ProtocalHandler protocalHandler = new ProtocalHandler(owner.targetName); try { // 封装协议文本 string protocalText = protocalHandler.Pack("file_abort"); protocalText = protocalHandler.Append(protocalText, "file", safeFileNameBase64); // 发送 byte[] sendbuf = Encoding.ASCII.GetBytes(protocalText); SocketAsyncEventArgs saEA = new SocketAsyncEventArgs(); saEA.Completed += new EventHandler <SocketAsyncEventArgs>( SendCompletedDoNothing); saEA.SetBuffer(sendbuf, 0, sendbuf.Length); socket.SendAsync(saEA); } catch (Exception ex) { Trace.WriteLine("异常位置:StopToSendFile"); Trace.WriteLine(ex.Message); } }
/// <summary> /// 接受方: /// 收到的1次确认为私聊,记录对方的身份信息 /// 此时确定owner /// 发送2次确认 /// </summary> /// <param name="protocalHandler">接收到的协议的封装</param> public void newSocketChatNameReceived(ProtocalHandler protocalHandler) { try { // 对方用户名 string targetNameBase64 = protocalHandler.GetElementTextByTag("name"); string targetName = protocalHandler.Base64stringToString(targetNameBase64); // 打开私聊窗口 main.SetChatFormClient(this, targetName); // 2次确认,发送you = 对方(发起方)用户名 string protocalText = protocalHandler.Pack("init_chat_ok"); protocalText = protocalHandler.Append( protocalText, "you", targetNameBase64); byte[] sendbuf = Encoding.ASCII.GetBytes(protocalText); SocketAsyncEventArgs saEA = new SocketAsyncEventArgs(); saEA.Completed += new EventHandler <SocketAsyncEventArgs>( newSocketUsernameSendEventHandler); saEA.SetBuffer(sendbuf, 0, sendbuf.Length); socket.SendAsync(saEA); } catch (Exception ex) { Trace.WriteLine("异常位置:" + "newSocketChatNameReceived"); Trace.WriteLine(ex.Message); CloseSocket(); } }
/// <summary> /// 发送方: /// 发送文件的某个片段 /// </summary> /// <param name="seq">当前序号</param> private void sendingFilePack(uint seq) { ProtocalHandler protocalHandler = new ProtocalHandler(owner.targetName); // 封装协议文本 string protocalText = protocalHandler.Pack("file_data"); protocalText = protocalHandler.Append(protocalText, "file", safeFileNameBase64); protocalText = protocalHandler.Append(protocalText, "seq", seq.ToString()); uint len = FilePacker.BytesOfPack; if (seq == maxSeq - 1) { len = filePacker.GetSizeOfLastPack(); } protocalText = protocalHandler.Append(protocalText, "len", len.ToString()); // 文件内容 byte[] buf = filePacker.GetPack(seq); string dataBase64 = Convert.ToBase64String(buf, 0, (int)len); protocalText = protocalHandler.Append(protocalText, "data", dataBase64); int checksum = 0; for (int i = 0; i < len; i++) { checksum += buf[i]; } checksum = -checksum; protocalText = protocalHandler.Append(protocalText, "checksum", checksum.ToString()); try { // 发送 byte[] sendbuf = Encoding.ASCII.GetBytes(protocalText); SocketAsyncEventArgs saEA = new SocketAsyncEventArgs(); saEA.Completed += new EventHandler <SocketAsyncEventArgs>( SendCompletedDoNothing); saEA.SetBuffer(sendbuf, 0, sendbuf.Length); socket.SendAsync(saEA); } catch (Exception ex) { Trace.WriteLine("异常位置:SendingFilePack"); Trace.WriteLine(ex.Message); } }
/// <summary> /// 发送RTF文本 /// </summary> /// <param name="rtfToSend"></param> public void SendRtfText(string rtfToSend) { try { ProtocalHandler protocalHandler = new ProtocalHandler(main.MyName); string protocalText = protocalHandler.Pack( "chat_rtf", protocalHandler.StringToBase64string(rtfToSend)); byte[] sendbuf = Encoding.ASCII.GetBytes(protocalText); SocketAsyncEventArgs saEA = new SocketAsyncEventArgs(); saEA.Completed += new EventHandler <SocketAsyncEventArgs>( SendCompletedDoNothing); saEA.SetBuffer(sendbuf, 0, sendbuf.Length); socket.SendAsync(saEA); } catch (Exception ex) { Trace.WriteLine("异常位置:SendRtfText"); Trace.WriteLine(ex.Message); } }
/// <summary> /// 完成文件收发 /// </summary> private void finishSendingOrReceivingFile() { // 关定时器 sendTimeOutTimer.Stop(); // 关文件 if (filePacker != null) { filePacker.Close(); filePacker = null; } if (fileWriter != null) { fileWriter.Close(); fileWriter = null; } ProtocalHandler protocalHandler = new ProtocalHandler(); owner.BeginInvoke(owner.stopSendingOrReceivingFileDelegate, String.Format("文件{0}的收发已完成。", protocalHandler.Base64stringToString(safeFileNameBase64))); safeFileNameBase64 = null; }
/// <summary> /// 发起方: /// Socket连接完成的事件处理程序 /// 发送1次确认 /// </summary> /// <param name="sender"></param> /// <param name="ea"></param> public void createSocketCompletedEventHandler( object sender, EventArgs ea) { // 取得新建的Socket(如果连接成功) // 此Socket应等于this.socket SocketAsyncEventArgs socketAsyncEA = (SocketAsyncEventArgs)ea; Socket createdSocket = socketAsyncEA.ConnectSocket; if (createdSocket != null && createdSocket == socket) // 连接成功 { // 1次确认,发送name=自己(发起方)用户名 ProtocalHandler protocalHandler = new ProtocalHandler(main.MyName); string protocalText = protocalHandler.Pack("init_chat_request"); byte[] sendbuf = Encoding.ASCII.GetBytes(protocalText); SocketAsyncEventArgs saEA = new SocketAsyncEventArgs(); saEA.Completed += new EventHandler <SocketAsyncEventArgs>( createdSocketSendNameCompletedEventHandler); saEA.SetBuffer(sendbuf, 0, sendbuf.Length); createdSocket.SendAsync(saEA); } }
/// <summary> /// 发起方: /// 申请发送文件 /// </summary> /// <param name="fileName">文件名(含路径)</param> public void RequestToSendFile(string fileName) { // 打开文件 filePacker = new FilePacker(owner.fileName); maxSeq = filePacker.GetPackNumbers(); owner.BeginInvoke(owner.setProgressDelegate, (int)maxSeq); // 取得文件名,并将文件名编码以便使用 safeFileNameBase64 = owner.GetSafeFileName(fileName); ProtocalHandler protocalHandler = new ProtocalHandler(owner.targetName); safeFileNameBase64 = protocalHandler.StringToBase64string(safeFileNameBase64); // 封装协议文本 string protocalText = protocalHandler.Pack("file_requesttosend"); protocalText = protocalHandler.Append(protocalText, "file", safeFileNameBase64); protocalText = protocalHandler.Append(protocalText, "maxseq", maxSeq.ToString()); try { // 发送 byte[] sendbuf = Encoding.ASCII.GetBytes(protocalText); SocketAsyncEventArgs saEA = new SocketAsyncEventArgs(); saEA.Completed += new EventHandler <SocketAsyncEventArgs>( SendCompletedDoNothing); saEA.SetBuffer(sendbuf, 0, sendbuf.Length); socket.SendAsync(saEA); } catch (Exception ex) { Trace.WriteLine("异常位置:RequestToSendFile"); Trace.WriteLine(ex.Message); } }
/// <summary> /// 发起方: /// 收到2次确认,核对对方的身份信息 /// </summary> /// <param name="sender"></param> /// <param name="ea"></param> private void createSocketNameReceivedEventHandler( object sender, EventArgs ea) { try { SocketAsyncEventArgs socketAsyncEA = (SocketAsyncEventArgs)ea; // 获取文本 string rcvString = Encoding.ASCII.GetString(socketAsyncEA.Buffer); ProtocalHandler protocalHandler = new ProtocalHandler(main.MyName); // 判断是否是协议 if (!protocalHandler.SetXmlText(rcvString)) { throw new MyProtocalException( "不是有效的协议文本,找不到CSP2P标签"); } // 数据包类型 string type = protocalHandler.GetElementTextByTag("type"); if (type.Equals("closesocket")) // 对方要求关闭Socket { closeSocketWithoutSend(); } if (!type.Equals("init_gp_ok")) { throw new MyProtocalException( "不是有效的2次确认," + "找不到type标签或type不为init_gp_ok"); } // 对方用户名 string key = protocalHandler.GetElementTextByTag("name"); key = protocalHandler.Base64stringToString(key); if (!key.Equals(targetName)) { throw new MyProtocalException( "不是有效的2次确认," + "找不到name标签或接受方用户名不符"); } // 己方用户名 string myName = protocalHandler.GetElementTextByTag("you"); myName = protocalHandler.Base64stringToString(myName); if (!myName.Equals(main.MyName)) { throw new MyProtocalException( "2次确认发现错误,找不到you标签" + "或接受方返回的发送方用户名不符"); } // 开始通信 owner.BeginInvoke(owner.sendRTFDelegate, rtfToSend); rtfToSend = null; beginReceive(); } catch (Exception ex) { Trace.WriteLine("异常位置:" + "createSocketNameReceivedEventHandler"); Trace.WriteLine(ex.Message); CloseSocket(); } }
/// <summary> /// 收到一条数据 /// </summary> /// <param name="sender"></param> /// <param name="ea"></param> private void receiveOneEventHandler(object sender, EventArgs ea) { try { SocketAsyncEventArgs socketAsyncEA = (SocketAsyncEventArgs)ea; // 获取文本 string rcvString = Encoding.ASCII.GetString(socketAsyncEA.Buffer); ProtocalHandler protocalHandler = new ProtocalHandler(); // 判断是否是协议 protocalHandler.SetXmlText(rcvString); // 对方用户名 string targetNameBase64 = protocalHandler.GetElementTextByTag("name"); string targetName = protocalHandler.Base64stringToString(targetNameBase64); if (targetName == null) { throw new MyProtocalException( "不是有效协议," + "找不到name标签或无法解码"); } // 类型 string type = protocalHandler.GetElementTextByTag("type"); if (type == null) { throw new MyProtocalException( "不是有效的协议文本,找不到type标签"); } else { switch (type) { case "ctl_closesocket": // 对方要求关闭Socket closeSocketWithoutSend(); break; case "gp_rtf": // 收到聊天消息(RTF文本) string rtfText = protocalHandler.GetElementTextByTag("data"); if (rtfText == null) { throw new MyProtocalException( "不是有效的协议文本,type为gp_rtf但找不到data标签"); } rtfText = protocalHandler.Base64stringToString(rtfText); if (rtfText == null) { throw new MyProtocalException( "不是有效的协议文本,rtf文本解码错误"); } // 显示收到的消息 owner.BeginInvoke(owner.receiveRTFDelegate, new object[] { rtfText }); break; default: throw new MyProtocalException("type类型未知: " + type); } // End Switch } } catch (Exception ex) { Trace.WriteLine("异常位置:P2PGroupClient.receiveOneEventHandler"); Trace.WriteLine(ex.Message); } finally { // 继续接收数据 if (socket != null) { beginReceive(); } } }
/// <summary> /// 收到的协议是file类型时的判断 /// </summary> /// <param name="type">类型</param> /// <param name="protocalHandler">协议处理类</param> protected void ReceivedTypeFile(string type, ProtocalHandler protocalHandler) { // 文件收发时接收到的文件名 string receivedSafeFileNameBase64 = protocalHandler.GetElementTextByTag("file"); try { switch (type) { case "file_requesttosend": // 收到接收文件的请求 if (owner.showPanelFile) { // 直接拒收 DeniedToFile(); break; } if (receivedSafeFileNameBase64 == null) { throw new MyProtocalException( "不是有效的协议文本,type为file但找不到file标签"); } string receivedSafeFileName = protocalHandler.Base64stringToString(receivedSafeFileNameBase64); if (receivedSafeFileName == null) { throw new MyProtocalException( "不是有效的协议文本,文件名解码错误"); } safeFileNameBase64 = receivedSafeFileNameBase64; maxSeq = Convert.ToUInt32( protocalHandler.GetElementTextByTag("maxseq")); owner.BeginInvoke(owner.setProgressDelegate, (int)maxSeq); currentSeq = 0; // 让用户选择是否接收文件 owner.BeginInvoke(owner.askedForReceivingFileDelegate, receivedSafeFileName); break; case "file_cleartosend": if (!owner.showPanelFile) { // 拒收 StopToSendFile(); break; } // 检查文件名匹配情况 CheckFileName(receivedSafeFileNameBase64); // 开始发送 try { owner.sendingOrReceivingFile = true; owner.BeginInvoke(owner.startTimingDelegate); sendingFilePack(0); } catch (Exception ex) { Trace.WriteLine("无法开始发送文件。"); throw ex; } break; case "file_denied": // 发文件的请求被拒绝 if (!owner.showPanelFile) { // 没有在准备收发文件的状态 break; } if (owner.sendingOrReceivingFile) { // 已经在收发文件,取消的type应该为file_abort StopToSendFile(); break; } // 检查文件名匹配情况 CheckFileName(receivedSafeFileNameBase64); // 取消文件发送 fileDenied(); break; case "file_data": // 检查是否正在收发文件 CheckWhileSendingOrReceiving(); // 超时定时器重置 sendTimeOutTimer.Start(); // 检查文件名匹配情况 CheckFileName(receivedSafeFileNameBase64); string seqString = protocalHandler.GetElementTextByTag("seq"); uint receivedSeq = Convert.ToUInt32(seqString); string data = protocalHandler.GetElementTextByTag("data"); byte[] buf = Convert.FromBase64String(data); // 检查checksum uint len = Convert.ToUInt32( protocalHandler.GetElementTextByTag("len")); int checksum = Convert.ToInt32( protocalHandler.GetElementTextByTag("checksum")); for (uint i = 0; i < len; i++) { checksum += buf[i]; } // 顺序正确 && 校验正确 if (receivedSeq == currentSeq && checksum == 0) { owner.BeginInvoke(owner.showProgressDelegate, (int)currentSeq); fileWriter.WriteBytes(currentSeq, buf, len); sendAck(++currentSeq); if (currentSeq >= maxSeq) { finishSendingOrReceivingFile(); } } else { sendAck(currentSeq); } break; case "file_ack": // 检查是否正在收发文件 CheckWhileSendingOrReceiving(); // 检查文件名匹配情况 CheckFileName(receivedSafeFileNameBase64); string ackString = protocalHandler.GetElementTextByTag("ack"); receivedAck(Convert.ToUInt32(ackString)); break; case "file_abort": if (!owner.showPanelFile) { // 没有在准备收发文件的状态 break; } if (!owner.sendingOrReceivingFile) { // 没有正在收发文件 break; } // 取消文件发送 owner.BeginInvoke(owner.stopSendingOrReceivingFileDelegate, String.Format("文件{0}的收发已被取消。", protocalHandler.Base64stringToString(safeFileNameBase64))); fileAborted(); break; default: throw new MyProtocalException("协议类型未知"); //break; } } catch (Exception ex) { Trace.WriteLine("异常位置:ReceivedTypeFile"); Trace.WriteLine(ex.Message); sendErrCount++; if (owner.sendingOrReceivingFile) { sendAck(currentSeq); } //StopToSendFile(); } }
/// <summary> /// 接受方 /// 收到1次确认,判断连接的类型 /// </summary> /// <param name="sender"></param> /// <param name="ea"></param> private void firstAckReceivedEventHandler( object sender, EventArgs ea) { Socket rcvSocket = sender as Socket; try { // 接收到的异步Socket事件参数 SocketAsyncEventArgs socketAsyncEA = (SocketAsyncEventArgs)ea; // 提取接收到的文本 string rcvString = Encoding.ASCII.GetString(socketAsyncEA.Buffer); ProtocalHandler protocalHandler = new ProtocalHandler(MyName); // 是否是协议 if (!protocalHandler.SetXmlText(rcvString)) { throw new MyProtocalException( "不是有效的协议文本,找不到CSP2P标签"); } // 数据包类型 string type = protocalHandler.GetElementTextByTag("type"); if (type == null) { throw new MyProtocalException( "不是有效的1次确认,找不到type标签"); } if (type.Equals("closesocket")) // 对方要求关闭Socket { rcvSocket.Close(); } // 对方用户名 string targetNameBase64 = protocalHandler.GetElementTextByTag("name"); string targetName = protocalHandler.Base64stringToString(targetNameBase64); if (targetName == null) { throw new MyProtocalException( "不是有效的1次确认," + "找不到name标签"); } if (type.Equals("init_chat_request")) // 私聊 { P2PChatClient socketHandler = new P2PChatClient(this, rcvSocket); socketHandler.newSocketChatNameReceived(protocalHandler); } else if (type.Equals("init_gp_request")) // 群聊 { P2PGroupClient socketHandler = new P2PGroupClient(this, rcvSocket); socketHandler.newSocketGroupNamesReceived(protocalHandler); } else { throw new MyProtocalException( "不是有效的1次确认," + "type不为init_chat_request或init_gp_request"); } // 记录对方地址 if (remoteIPaddress.ContainsKey(targetName)) { remoteIPaddress[targetName] = new IPInfo((IPEndPoint)rcvSocket.RemoteEndPoint); } else { remoteIPaddress.Add(targetName, new IPInfo((IPEndPoint)rcvSocket.RemoteEndPoint)); } } catch (Exception ex) { Trace.WriteLine("异常位置:" + "firstAckReceivedEventHandler"); Trace.WriteLine(ex.Message); // 直接关闭socket try { rcvSocket.Close(); } catch (Exception ex2) { Trace.WriteLine("异常位置:" + "firstAckReceivedEventHandler出错关闭rcvSocket时"); Trace.WriteLine(ex2.Message); } } }