p2p 通信问题
大家好:我是个小菜鸟,刚刚接触网络编程,老师要求我们写一个视频聊天和文件发送的程序。我根据网络应用编程的书上改写了一份,但是中间很多问题:(1)文件传输和视频聊天的不能同时进行;
(2)视频聊天时候,开启调试,视频刚打开就关上了;
(3)双方视频聊天时候有一方不能接收视频,只能发送视频。
求路过的大神帮忙,解决一下啊!
源码:using System;
using System.Collections.Generic;
using
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using
using
using
using
using System.Drawing.Imaging;
using System.Windows.Media.Imaging;
namespace sheji
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.FormBorderStyle = FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
registerAndResolve();
udpChat = new UdpChat(this);
}
/************摄像头****************/
WebCamera myCamera = new WebCamera(); //摄像头对象
int device_number = 0; //摄像头编号
bool bLocalShow = false; //是否正在预览
bool bCallRemote = false; //是否进行视频呼叫
IDataObject data;
Image bmap;
/************对等通信用*************/
//自定义对等点名称
String strpeerName = "Myp2pVedio";
TcpListener listener;
TcpClient localclient;
User user;
BinaryWriter localbw;
BinaryReader localbr;
NetworkStream localsr;
String remotePort = "";
String remoteIP = "";
Thread thredRece; //接收视频信息
Thread thredListen;//接受连接请求
MemoryStream receiveMS;//保存一帧图片
int receiveLength;//一帧图片的长度
bool isExit = false;//是否停止接收视频信息
UdpChat udpChat;//发送聊天信息
List<ListViewItem> resolvedListViewItem = new List<ListViewItem>();
int i = 0;//表示选定的视频源
private void registerAndResolve()
{
getPort();
//将本应用使用的IP地址及端口号,注册到群中
if (!MyPNRP.registerPeer(strpeerName))
MessageBox.Show("未开启点对点服务");
//定期解析对等点所在群的同名对等节点的信息
Thread resolveThread = new Thread(Resolve);
resolveThread.Start();
resolveThread.IsBackground = true;
Start_Receiving_Video_Conference();
startrecefile();
}
/// <summary>
/// 获取一个可用端口号,启动监听
/// </summary>
public void getPort()
{
while (true)
{
//设置本应用使用的端口号
MyPNRP.port = new Random().Next(50000, 51000);
try
{
listener = new TcpListener(IPAddress.Any, MyPNRP.port);
listener.Start();
}
catch
{
continue;
}
break;
}
}
/// <summary>
/// 解析名称
/// </summary>
private void Resolve()
{
while (!isExit)
{
PeerNameRecordCollection recColl = MyPNRP.ResolverPeer(strpeerName);
resolvedListViewItem.Clear();
foreach (PeerNameRecord record in recColl)
{
foreach (IPEndPoint endP in record.EndPointCollection)
{
if (endP.AddressFamily.Equals(AddressFamily.InterNetwork))
{
ListViewItem item1 = new ListViewItem(endP.ToString());
resolvedListViewItem.Add(item1);
}
}
}
//检查是否有其他终端退出,如已经退出则从列表中删除该项
if (resolvedListViewItem.Count == 0)
ClearItems();
else
RemoveItem();
foreach (PeerNameRecord record in recColl)
{
foreach (IPEndPoint endP in record.EndPointCollection)
{
if (endP.AddressFamily.Equals(AddressFamily.InterNetwork))
{
ListViewItem item1 = new ListViewItem(endP.ToString());
AppendItem(item1);
}
}
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
listBox1.Items.Clear();
string name = Dns.GetHostName();
IPHostEntry localip = Dns.GetHostEntry(name);
listBox1.Items.Add("本机ip:");
foreach (IPAddress ip in localip.AddressList)
{
listBox1.Items.Add(ip);
}
}
private void button5_Click(object sender, EventArgs e)
{
this.textBox2.Text = "";
}
private void button4_Click(object sender, EventArgs e)
{
try
{
remoteIP = listView1.SelectedItems[0].ToString().Split(':')[1];
remoteIP = remoteIP.Substring(2, remoteIP.Length - 2);
udpChat.sendData(remoteIP, remotePort, this.textBox2.Text);
}
catch
{
MessageBox.Show("请选择正确接收方");
}
}
private void text_keypress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter)
{
remoteIP = listView1.SelectedItems[0].ToString().Split(':')[1];
remoteIP = remoteIP.Substring(2, remoteIP.Length - 2);
udpChat.sendData(remoteIP, remotePort, this.textBox2.Text);
}
}
private void button1_Click(object sender, EventArgs e)
{
//呼叫视频请求
if (!bCallRemote)
{
try
{
remotePort = this.listView1.SelectedItems[0].ToString().Split(':')[2].Substring(0, 5);
remoteIP = listView1.SelectedItems[0].ToString().Split(':')[1];
remoteIP = remoteIP.Substring(2, remoteIP.Length - 2);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
MessageBox.Show("未选择远程主机");
return;
}
if (bLocalShow == false && Start_Sending_Video_Conference())
{
if (LocalVedioShow())
{
bLocalShow = true;
this.button2.Text = "取消预览";
}
}
}
else
{
label1.Text = "视频中断";
if (localclient != null)
{
try
{
timersend.Stop();
button2_Click(null, null);
localbw.Write("stop:false");
localclient.Close();
localbw.Close();
localsr.Close();
localbr.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
this.button1.Text = "视频呼叫";
bCallRemote = false;
}
}
/// <summary>
/// 开始发送数据
/// </summary>
private bool Start_Sending_Video_Conference()
{
try
{
localclient = new TcpClient(remoteIP, int.Parse(remotePort));//Connecting with server
localsr = localclient.GetStream();
localbw = new BinaryWriter(localsr);
localbr = new BinaryReader(localsr);
localbw.Write("Query:false");
if (localbr.ReadString() == "OK:false")
{
timersend.Enabled = true;
timersend.Start();
label1.Text = "开始视频发送";
this.button1.Text = "中断视频";
bCallRemote = true;
return true;
}
else
{
this.button1.Text = "视频呼叫";
label1.Text = "远程主机未对视频请求做出响应";
localbw.Close();
localbr.Close();
return false;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
this.button1.Text = "视频呼叫";
label1.Text = "远程主机未对视频请求做出响应";
return false;
}
}
/// <summary>
/// 准备接收视频
/// </summary>
private void Start_Receiving_Video_Conference()
{
thredListen = new Thread(ReceiveConnect); // Start Thread Session
thredListen.Start();
thredListen.IsBackground = true;
}
/// <summary>
/// 接收连接请求
/// </summary>
private void ReceiveConnect()
{
while (!isExit)
{
TcpClient remoteClient = listener.AcceptTcpClient();
isExit = false;
user = new User(remoteClient);
thredRece = new Thread(ReceiveMessage);
thredRece.IsBackground = true;
thredRece.Start(user);
}
}
/// <summary>
/// 接收信息
/// </summary>
private void ReceiveMessage(Object myUser)
{
User user = (User)myUser;
while (!isExit)
{
//保存接收的命令字符串
string receiveString = null;
//解析命令用
//每条命令均带有一个参数,值为true或者false,表示是否有紧跟的字节数组
string[] splitString = null;
byte[] receiveBytes = null;
try
{
//从网络流中读出命令字符串
//此方法会自动判断字符串长度前缀,并根据长度前缀读出字符串
receiveString = user.br.ReadString();
splitString = receiveString.Split(':');
if (splitString[1] == "true")
{
//先从网络流中读出32位的长度前缀
receiveLength = user.br.ReadInt32();
//然后读出指定长度的内容保存到字节数组中
receiveBytes = user.br.ReadBytes(receiveLength);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
//this.pictureBoxFriend.Image = (System.Drawing.Image)Resources.ResourceManager.GetObject("vedio");
//底层套接字不存在时会出现异常
SetlabelTips("接收数据失败");
break;
}
if (receiveString == null)
{
if (isExit == false)
{
//this.pictureBoxFriend.Image = (System.Drawing.Image)Resources.ResourceManager.GetObject("vedio");
SetlabelTips("接收数据失败");
}
break;
}
SetlabelTips("收到:" + receiveString);
switch (splitString[0])
{
case "Query":
//询问是否接受视频请求
if (MessageBox.Show(String.Format("接收{0}视频请求", user.remoteClient.Client.RemoteEndPoint), "消息", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
user.bw.Write("OK:false");
}
else
user.bw.Write("NO:false");
break;
case "Image":
//传递图片
try
{
//利用接收到得字节数组创建内存流
receiveMS = new MemoryStream(receiveBytes);
//从流中获取图片
this.pictureBox1.Image = Image.FromStream(receiveMS);
//关闭内存流
receiveMS.Close();
//清空内存流
receiveMS.Flush();
//重置内存流
receiveMS = null;
}
catch (Exception ex)
{
MessageBox.Show("接收图片错误");
Console.WriteLine(ex.ToString());
break;
}
break;
case "Stop":
//停止接收视频
//this.pictureBoxFriend.Image = (System.Drawing.Image)Resources.ResourceManager.GetObject("vedio");
isExit = true;
break;
default:
break;
}
}
}
private bool LocalVedioShow()
{
//设定设备信息
myCamera.IDevice = device_number;
//开始在本地预览显示
if (!myCamera.OpenPreviewWindow(this.pictureBox2))
{
MessageBox.Show("视频预览失败!请检查摄像头设备是否连接正常,驱动是否安装!");
return false;
}
return true;
}
/// <summary>
/// 发送视频数据
/// </summary>
private void Send_One_Capture(BinaryWriter bw)
{
//将字节数组存放到内存流中
MemoryStream ms = new MemoryStream();
try
{
//将摄像头的一帧数据存放到剪贴板中
myCamera.CaptureWindow();
//从剪贴板中获取图片
data = Clipboard.GetDataObject();
//将截图存放到内存流中
if (data.GetDataPresent(typeof(System.Drawing.Bitmap)))
{
bmap = ((Image)(data.GetData(typeof(System.Drawing.Bitmap))));
bmap.Save(ms, ImageFormat.Bmp);
}
//将截图以JPEG形式保存到内存流中
this.pictureBox2.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
//从流中获取字节数组
byte[] arrImage = ms.GetBuffer();
bw.Write("Image:true");
//写入数据长度
bw.Write(arrImage.Length);
//发送图片
bw.Write(arrImage);
ms.Flush();
bw.Flush();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
button1_Click (null, null);
bw.Close();
}
ms.Close();
}
private void timersend_Tick_1(object sender, EventArgs e)
{
Send_One_Capture(localbw);
}
/// <summary>
/// 多线程访问控件
/// </summary>
/// <param name="item"></param>
delegate void AppendItemDelegate(ListViewItem item);
public void AppendItem(ListViewItem item)
{
if (listView1.InvokeRequired)
{
AppendItemDelegate d = AppendItem;
listView1.Invoke(d, item);
}
else
{
Boolean exist = false;
foreach (ListViewItem myitem in listView1.Items)
{
if (myitem.Text.Equals(item.Text))
{
exist = true;
}
}
if (!exist)
listView1.Items.Add(item);
}
}
/// <summary>
/// 删除已经推出对等点的ListItem项
/// </summary>
delegate void RemoveItemDelegate();
public void RemoveItem()
{
if (listView1.InvokeRequired)
{
RemoveItemDelegate d = RemoveItem;
listView1.Invoke(d);
}
else
{
bool exist;
foreach (ListViewItem itemUser in listView1.Items)
{
exist = false;
foreach (ListViewItem itemResolveNew in resolvedListViewItem)
{
if (itemUser.Text.Equals(itemResolveNew.Text))
{
exist = true;
break;
}
}
if (!exist)
listView1.Items.Remove(itemUser);
}
}
}
/// <summary>
/// 清空所有ListItem项
/// </summary>
delegate void ClearItemDelegate();
public void ClearItems()
{
if (listView1.InvokeRequired)
{
ClearItemDelegate d = ClearItems;
listView1.Invoke(d);
}
else
{
listView1.Items.Clear();
}
}
/// <summary>
/// 清空发送框
/// </summary>
delegate void ClearRichTextBoxSendDelegate();
public void ClearRichTextBox()
{
if (this.textBox2.InvokeRequired)
{
ClearRichTextBoxSendDelegate d = ClearRichTextBox;
textBox2.Invoke(d);
}
else
{
textBox2.Clear();
textBox2.Focus();
}
}
delegate void SetRichTextBoxReceiveDelegate(String text);
public void SetRichTextBoxReceive(String text)
{
if (this.textBox2.InvokeRequired)
{
SetRichTextBoxReceiveDelegate d = SetRichTextBoxReceive;
this.textBox1.Invoke(d, text);
}
else
{
textBox1.AppendText(text);
textBox1.AppendText(Environment.NewLine);
}
}
delegate void SetlabelTipsDelegate(String text);
public void SetlabelTips(String text)
{
if (this.label1.InvokeRequired)
{
SetlabelTipsDelegate d = SetlabelTips;
this.label1.Invoke(d, text);
}
else
{
label1.Text = text;
}
}
private void button2_Click(object sender, EventArgs e)
{
//开始预览
if (bLocalShow == false)
{
if (LocalVedioShow())
{
bLocalShow = true;
this.button2.Text = "取消预览";
}
}
else
{
myCamera.ClosePreviewWindow();
bLocalShow = false;
this.button2.Text = "本地预览";
}
}
private void button3_Click(object sender, EventArgs e)
{
if (bLocalShow == true)
{
if(i==1)
{
//给对方拍照
}
else
{
myCamera.CaptureWindow();
data = Clipboard.GetDataObject();
if (data.GetDataPresent(typeof(Bitmap)))
{
bmap = (Image)data.GetData(typeof(Bitmap));
string savefile = @"D:\" + DateTime.Now.ToFileTime().ToString()+".jpg" ;
bmap.Save(savefile, ImageFormat.Jpeg);
}
}
}
else
{
MessageBox.Show("请选择视频源");
}
}
//关闭窗体
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
isExit = true;
if (timersend.Enabled)
{
timersend.Stop();
timersend.Enabled = false;
}
if (localclient != null)
{
if (localclient.Connected)
localclient.Close();
}
if (user != null)
{
user.remoteClient.Close();
user.br.Close();
user.bw.Close();
}
myCamera.ClosePreviewWindow();
}
private void pictureBox1_Click(object sender, EventArgs e)
{
i = 1;
}
/////////文件操作////////
private int size = 66530000;
private void filesend()
{
string strpath = "";
int num = 0;
DialogResult result;
OpenFileDialog dlg = new OpenFileDialog();
dlg.InitialDirectory = @"C:\";
dlg.Filter = "图片(*.jpg,*.gif.*.bmp)|*.jpg,*.gif,*.bmp|文本文件(*.txt)|*.txt|All Files(*.*)|(*.*)";
result = dlg.ShowDialog();
strpath = dlg.FileName;
try
{
remotePort = this.listView1.SelectedItems[0].ToString().Split(':')[2].Substring(0, 5);
remoteIP = listView1.SelectedItems[0].ToString().Split(':')[1];
remoteIP = remoteIP.Substring(2, remoteIP.Length - 2);
TcpClient client = new TcpClient(remoteIP, int.Parse(remotePort));//连接远程服务器
NetworkStream ns = client.GetStream();//获取网络流
BinaryReader lbr = new BinaryReader(ns);
BinaryWriter lbw = new BinaryWriter(ns);
if (result == DialogResult.OK)
{
lbw.Write("ready:false");//写入准备(即发送文件前的询问 )
if (lbr.ReadString() == "ok")//如果从网络中读取(即对方发送的是ok)
{
FileStream fs = new FileStream(strpath, FileMode.Open, FileAccess.Read);
double ld = fs.Length;
while (ld > 0 && ns.CanWrite)
{
byte[] bytes = new byte[size];
num = fs.Read(bytes, 0, bytes.Length);
ns.Write(bytes, 0, num);
ld -= num;
label1.Text = "文件发送中...";
}
fs.Close();
ns.Close();
localbw.Close();
MessageBox.Show("文件发送完成");
label2.Text = "文件发送提示";
}
else
{
MessageBox.Show("对方拒绝接收");
}
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
private void button6_Click(object sender, EventArgs e)
{
try
{
filesend();
}
catch
{
MessageBox.Show("请选择正确的主机");
}
}
private void receviefile(object myuse)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
User user = (User)myuse;
string receivestring = null;
string[] splitstring = null;
receivestring = user.br.ReadString();
splitstring = receivestring.Split(':');
switch (splitstring[0])
{
case "ready":
if (MessageBox.Show(String.Format("接收{0}文件", user.remoteClient.Client.RemoteEndPoint), "消息", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
user.bw.Write("ok");
try
{
int num = 0;
int len = 0;
if (user.stream != null)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "所有文件|*.txt";
if (sfd.ShowDialog(this) == DialogResult.OK)
{
string filesavepath = sfd.FileName;
FileStream fm = new FileStream(filesavepath, FileMode.Create, FileAccess.Write);
byte[] buffer = new byte[512];
while ((num = user.stream.Read(buffer, 0, buffer.Length)) > 0)
{
fm.Write(buffer, 0, num);
len += num;
}
fm.Close();
user.stream.Close();
MessageBox.Show("文件接收完成!");
}
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
break;
}
else
{
user.bw.Write("no");
}
break;
default:
break;
}
}
private void startrecefile()
{
Thread thredlisten = new Thread(receconnect);
thredlisten.Start();
thredlisten.IsBackground = true;
}
private void receconnect()
{
TcpClient remoteclient = listener.AcceptTcpClient();
user = new User(remoteclient);
Thread th = new Thread(receviefile);
th.IsBackground = true;
th.Start(user);
}
}
}