在一些好人的帮助下,我慢慢建立了一个小型的P2P应用程序,它发送和接收大约4kb的图像流。TCP发送简单的洪水控制和同步-P2P网络摄像头
在127.0.0.1接收跟上发送,但是当我在远程机器上尝试它时,在我看来接收无法跟上,我可能已发送6个图像,但接收方只收到一个...随着时间的流逝,差异会变得更大,直到你在另一个屏幕上看到自己整整一分钟。值得注意的是,我希望这可以在另一个国家的64kbps-100kbps的连接上运行良好,ping时间可能会非常长,如250ms或更长。
我有什么同步选项?
我的兄弟建议我实现1:1发送/接收的简单解决方案。所以我只收到一张图片时发送一张图片。
正如我在网络编程初学者总,任何其他提示是最欢迎的,这里是我的完整代码:
namespace MyPrivateChat
{
using System;
using System.Drawing;
using System.Windows.Forms;
using AForge.Video;
using AForge.Video.DirectShow;
using System.Drawing.Imaging;
using System.IO;
using System.Net;
using System.Text.RegularExpressions;
using System.Net.Sockets;
using System.Diagnostics;
using AForge.Imaging.Filters;
public partial class fChat : Form
{
public fChat()
{
InitializeComponent();
}
private void fChat_Load(object sender, EventArgs e)
{
// get ip
_ownExternalIp = GetPublicIP();
Text = "My Private Chat - IP: " + _ownExternalIp;
// get video cam
var _videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
if (_videoDevices.Count != 0)
{
_videoDevice = new VideoCaptureDevice(_videoDevices[0].MonikerString);
btnStart.Enabled = true;
}
// fire up listener
listeningThread.RunWorkerAsync();
}
public string GetPublicIP()
{
string ip = "";
using (WebClient wc = new WebClient())
{
Match m = Regex.Match(wc.DownloadString("http://checkip.dyndns.org/"), @"(?<IP>\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})");
if (m.Success)
{
ip = m.Groups["IP"].Value;
}
}
return ip;
}
private void mnuPasteOwnIP_Click(object sender, EventArgs e)
{
txtPartnerIP.Text = _ownExternalIp;
}
private void btnStart_Click(object sender, EventArgs e)
{
if (_tcpOut == null)
{
// tcp server setup
_tcpOut = new TcpClient();
_tcpOut.Connect(txtPartnerIP.Text, 54321);
tmrLive.Enabled = true;
}
else
{
tmrLive.Enabled = false;
_tcpOut.Client.Disconnect(true);
_tcpOut.Close();
_tcpOut = null;
}
if (!_videoDevice.IsRunning)
{
_videoDevice.NewFrame += new NewFrameEventHandler(NewFrameReceived);
_videoDevice.DesiredFrameSize = new Size(640, 480);
_videoDevice.DesiredFrameRate = 100;
_videoDevice.Start();
btnStart.Text = "Stop";
}
else
{
_videoDevice.SignalToStop();
btnStart.Text = "Start";
}
}
private void NewFrameReceived(object sender, NewFrameEventArgs e)
{
Bitmap img = (Bitmap)e.Frame.Clone();
byte[] imgBytes = EncodeToJpeg(img, 25).ToArray();
if (_tcpOut.Connected)
{
NetworkStream ns = _tcpOut.GetStream();
if (ns.CanWrite)
{
ns.Write(BitConverter.GetBytes(imgBytes.Length), 0, 4);
ns.Write(imgBytes, 0, imgBytes.Length);
_totalFramesSent++;
}
}
}
private void listeningThread_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
_tcpIn = new TcpListener(IPAddress.Any, 54321);
_tcpIn.Start();
TcpClient _inClient = _tcpIn.AcceptTcpClient();
lblStatus.Text = "Connected - Receiving Broadcast";
tmrLive.Enabled = true;
NetworkStream ns = _inClient.GetStream();
while (true)
{
// read image size.
Byte[] imgSizeBytes = new Byte[4];
int totalBytesRead = 0;
do
{
int bytesRead = ns.Read(imgSizeBytes, totalBytesRead, 4 - totalBytesRead);
if (bytesRead == 0)
{
break; // problem
}
totalBytesRead += bytesRead;
} while (totalBytesRead < 4);
// read image
int imgSize = BitConverter.ToInt32(imgSizeBytes, 0);
Byte[] imgBytes = new Byte[imgSize];
totalBytesRead = 0;
do
{
int bytesRead = ns.Read(imgBytes, totalBytesRead, imgSize - totalBytesRead);
if (bytesRead == 0)
{
break; // problem
}
totalBytesRead += bytesRead;
} while (totalBytesRead < imgSize);
picVideo.Image = Image.FromStream(new MemoryStream(imgBytes));
_totalFramesReceived++;
}
}
private void CloseVideoDevice()
{
if (_videoDevice != null)
{
if (_videoDevice.IsRunning)
{
_videoDevice.SignalToStop();
}
_videoDevice = null;
}
}
private void fChat_FormClosing(object sender, FormClosingEventArgs e)
{
CloseVideoDevice();
}
private void btnClose_Click(object sender, EventArgs e)
{
Close();
}
private void tmrLive_Tick(object sender, EventArgs e)
{
_totalSecondsLive++;
lblStats.Text = "S:"+_totalFramesSent + " R:" + _totalFramesReceived + " T:"+ _totalSecondsLive;
if (_totalSecondsLive == 60)
{
MessageBox.Show("Total Frames : " + _totalFramesSent);
}
}
#region ENCODING JPEG
private MemoryStream EncodeToJpeg(Bitmap img, long quality)
{
using (EncoderParameters myEncoderParameters = new EncoderParameters(1))
{
MemoryStream ms = new MemoryStream();
myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, quality);
img.Save(ms, GetEncoder(ImageFormat.Jpeg), myEncoderParameters);
return ms;
}
}
private ImageCodecInfo GetEncoder(ImageFormat format)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
foreach (ImageCodecInfo codec in codecs)
{
if (codec.FormatID == format.Guid)
{
return codec;
}
}
return null;
}
#endregion
VideoCaptureDevice _videoDevice;
TcpClient _tcpOut;
TcpListener _tcpIn;
string _ownExternalIp;
int _totalFramesSent;
int _totalFramesReceived;
int _totalSecondsLive;
}
}
谢谢,这是类似于我已经提出了什么。这个“确认”会是更好的小布尔值还是更好地等待来自相反方向的图像作为确认? – sprocket12 2012-01-13 09:47:06
编辑......... – usr 2012-01-13 09:55:24
感谢您的想法,他们很简单,在我的范围内。当与上面的Eugen Rieck建议的变量jpeg压缩相结合时,希望也能有效。 – sprocket12 2012-01-13 12:10:54