C# TCP发送简单的洪水控制和同步-P2P网络摄像头

C# TCP发送简单的洪水控制和同步-P2P网络摄像头,c#,sockets,networking,tcp,webcam,C#,Sockets,Networking,Tcp,Webcam,在SO的一些好心人的帮助下,我慢慢地构建了一个小型P2P应用程序,可以发送和接收大约4kb的图像流 在127.0.0.1上,接收与发送保持同步,但当我在远程机器上尝试时,似乎接收无法跟上,我可能已发送了6个图像,但接收器到目前为止只收到一个。。。随着时间的推移,差异越来越大,直到你在另一个屏幕上看到一整分钟前的自己。值得注意的是,在另一个ping时间可能非常大(如250ms或更高)的国家,我希望它能在64kbps-100kbps的连接上正常工作 我有哪些同步选项 我哥哥告诉我一个简单的解决方案,

在SO的一些好心人的帮助下,我慢慢地构建了一个小型P2P应用程序,可以发送和接收大约4kb的图像流

在127.0.0.1上,接收与发送保持同步,但当我在远程机器上尝试时,似乎接收无法跟上,我可能已发送了6个图像,但接收器到目前为止只收到一个。。。随着时间的推移,差异越来越大,直到你在另一个屏幕上看到一整分钟前的自己。值得注意的是,在另一个ping时间可能非常大(如250ms或更高)的国家,我希望它能在64kbps-100kbps的连接上正常工作

我有哪些同步选项

我哥哥告诉我一个简单的解决方案,那就是实现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;
    }
}
名称空间MyPrivateChat
{
使用制度;
使用系统图;
使用System.Windows.Forms;
使用大屏幕视频;
使用forge.Video.DirectShow;
使用系统、绘图、成像;
使用System.IO;
Net系统;
使用System.Text.RegularExpressions;
使用System.Net.Sockets;
使用系统诊断;
使用热成像滤光片;
公共部分类fChat:Form
{
公共fChat()
{
初始化组件();
}
私有void fChat_加载(对象发送方,事件参数e)
{
//获取ip
_ownExternalIp=GetPublicIP();
Text=“我的私人聊天-IP:”+\u-ownExternalIp;
//拿摄像机
var _videoDevices=新的FilterInfoCollection(FilterCategory.VideoInputDevice);
如果(\u videoDevices.Count!=0)
{
_videoDevice=新的VideoCaptureDevice(\u videoDevices[0]。监视器字符串);
btnStart.Enabled=true;
}
//激发听众
listingThread.RunWorkerAsync();
}
公共字符串GetPublicIP()
{
字符串ip=“”;
使用(WebClient wc=new WebClient())
{
Match m=Regex.Match(wc.DownloadString(“http://checkip.dyndns.org/“(?\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}”);
如果(m.成功)
{
ip=m.组[“ip”]值;
}
}
返回ip;
}
私有void mnuPasteOwnIP\u单击(对象发送方,事件参数e)
{
Text=\u ownExternalIp;
}
私有void btnStart_单击(对象发送方,事件参数e)
{
如果(_tcpOut==null)
{
//tcp服务器设置
_tcpOut=新的TcpClient();
_tcpOut.Connect(txtPartnerIP.Text,54321);
tmrLive.Enabled=true;
}
其他的
{
tmrLive.Enabled=false;
_tcpOut.Client.Disconnect(true);
_tcpOut.Close();
_tcpOut=null;
}
如果(!\u videoDevice.IsRunning)
{
_videoDevice.NewFrame+=新的NewFrameEventHandler(NewFrameReceived);
_videoDevice.DesiredFrameSize=新尺寸(640480);
_videoDevice.DesiredFrameRate=100;
_videoDevice.Start();
btnStart.Text=“停止”;
}
其他的
{
_videoDevice.SignalToStop();
btnStart.Text=“开始”;
}
}
私有void NewFrameReceived(对象发送方,NewFrameEventArgs e)
{
位图img=(位图)e.Frame.Clone();
字节[]imgBytes=EncodeToJpeg(img,25).ToArray();
如果(_tcpOut.Connected)
{
NetworkStream ns=\u tcpOut.GetStream();
如果(ns.CanWrite)
{
ns.Write(BitConverter.GetBytes(imgBytes.Length),0,4;
ns.写入(单位:百万字节,0,百万字节长度);
_totalFramesSent++;
}
}
}
私有void ListingThread_DoWork(对象发送方,System.ComponentModel.DoWorkEventArgs e)
{
_tcpIn=新的TcpListener(IPAddress.Any,54321);
_tcpIn.Start();
TcpClient _inClient=_tcpIn.AcceptTcpClient();
lblStatus.Text=“已连接-接收广播”;
tmrLive.Enabled=true;
NetworkStream ns=_inClient.GetStream();
while(true)
{
//读取图像大小。
字节[]imgSizeBytes=新字节[4];
int totalBytesRead=0;
做
{
int bytesRead=ns.Read(imgSizeBytes,totalBytesRead,4-totalBytesRead);
如果(字节读==0)
{
break;//问题
}
totalBytesRead+=字节读取;
}而(总字节数<4);
//读取图像
int imgSize=位转换器.ToInt32(imgSizeBytes,0);
字节[]imgBytes=新字节[imgSize];
totalBytesRead=0;
做
{
int bytesRead=ns.Read(imgBytes,totalBytesRead,imgSize-totalBytesRead);
如果(字节读==0)
{
break;//问题
}
totalBytesRead+=字节读取;
}while(totalBytesRead