[英]Proper sending and receiving via C# sockets?
我正在嘗試使用C#創建遠程桌面服務器和客戶端。 服務器捕獲屏幕,然后通過套接字將其發送給客戶端。 我使用下面的代碼,盡管它僅在客戶端上顯示jpeg圖像的一部分。 我認為這是因為圖像是在多個數據包中發送的,當前代碼僅讀取一個數據包並顯示它。 誰能解釋我將如何更改代碼,以便在顯示代碼之前接收多個數據包(整個圖像)。
服務器代碼:
Socket serverSocket;
Socket clientSocket;
public Form1()
{
InitializeComponent();
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
serverSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 8221);
serverSocket.Bind(ipEndPoint);
serverSocket.Listen(4);
//Accept the incoming clients
serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Stream Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop();
Rectangle bounds = new Rectangle(0, 0, 1280, 720);
Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height);
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
}
System.IO.MemoryStream stream = new System.IO.MemoryStream();
ImageCodecInfo myImageCodecInfo;
System.Drawing.Imaging.Encoder myEncoder;
EncoderParameter myEncoderParameter;
EncoderParameters myEncoderParameters;
myEncoderParameters = new EncoderParameters(1);
myImageCodecInfo = GetEncoderInfo("image/jpeg");
myEncoder = System.Drawing.Imaging.Encoder.Quality;
myEncoderParameter = new EncoderParameter(myEncoder, 40L);
myEncoderParameters.Param[0] = myEncoderParameter;
bitmap.Save(stream, myImageCodecInfo, myEncoderParameters);
byte[] imageBytes = stream.ToArray();
stream.Dispose();
clientSocket.Send(imageBytes);
timer1.Start();
}
如您所見,我使用的計時器的間隔設置為30,用於發送圖像字節。
客戶代碼:
public Socket clientSocket;
byte[] byteData = new byte[2048];
MemoryStream ms;
public Form1()
{
InitializeComponent();
backgroundWorker1.RunWorkerAsync();
this.DoubleBuffered = true;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
clientSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse("MY EXTERNAL IP HERE"), 8221);
//Connect to the server
clientSocket.BeginConnect(ipEndPoint,
new AsyncCallback(OnConnect), null);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "SGSclient",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
private void OnConnect(IAsyncResult ar)
{
try
{
//Start listening to the data asynchronously
clientSocket.BeginReceive(byteData,
0,
byteData.Length,
SocketFlags.None,
new AsyncCallback(OnReceive),
null);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Stream Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void OnReceive(IAsyncResult ar)
{
try
{
int byteCount = clientSocket.EndReceive(ar);
ms = new MemoryStream(byteData);
using (BinaryReader br = new BinaryReader(ms))
{
this.BackgroundImage = Image.FromStream(ms).GetThumbnailImage(this.ClientRectangle.Width, this.ClientRectangle.Height, null, IntPtr.Zero);
}
}
catch (ArgumentException e)
{
//MessageBox.Show(e.Message);
}
clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(OnReceive), null);
}
客戶應接收圖像,然后將其顯示在表單的背景上。
您需要在套接字通信中添加應用程序級別協議。
向所有發送的郵件添加標題。 標頭包含隨后的字節數。 它是更簡單的代碼,具有比計數終止序列更好的字節數性能。
然后,客戶端執行兩組讀取:1)讀取已知包含在任何標頭中的字節數。
2)從標題中提取字節數后,循環讀取直到獲得指示的字節數。
對於所有編寫套接字通信的人來說,必讀的文章: http : //nitoprograms.blogspot.com/2009/04/message-framing.html從該文章:重復此操作三遍:“ TCP對數據包不起作用數據。TCP在數據流上運行。”
您必須在映像的末尾設置一個定界符,這是一組字節,它將對映像已結束的服務器進行初始化。 也稱為文件結尾 (EOF)或消息結尾 。 TCP不會將映像分割為應用程序的邏輯數據包,因此您必須編寫自己的信息控制。
邏輯與此類似: CLIENT
byte[] EndOfMessage = System.Text.Encoding.ASCII.GetBytes("image_end");
byte[] ImageBytes = GetImageBytes();
byte[] BytesToSend = new byte[EndOfMessage.Length + ImageBytes.Length];
Array.Copy(ImageBytes, 0, BytesToSend);
Array.Copy(EndOfMessage, 0, BytesToSend, ImageBytes.Length, EndOfMessage.Length);
SendToServer(BytesToSend);
服務器
byte[] EndOfMessage = System.Text.Encoding.ASCII.GetBytes("image_end");
byte[] ReceivedBytes;
while(!IsEndOfMessage(ReceivedBytes, EndOfMessage ))
{
//continue reading from socket and adding to ReceivedBytes
}
ReceivedBytes = RemoveEndOfMessage(ReceivedBytes, EndOfMessage );
PrintImage(ReceivedBytes);
很抱歉,我現在正在工作,無法提供完整的示例。
問候
支持方式:
private bool IsEndOfMessage(byte[] MessageToCheck, byte[] EndOfMessage)
{
for(int i = 0; i++; i < EndOfMessage.Length)
{
if(MessageToCheck[MessageToCheck.Length - (EndOfMessage.Length + i)] != EndOfMessage[i])
return false;
}
return true;
}
private byte[] RemoveEndOfMessage(byte[] MessageToClear, byte[] EndOfMessage)
{
byte[] Return = new byte[MessageToClear.Length - EndOfMessage.Length];
Array.Copy(MessageToClear, Return, Return.Length);
return Return;
}
同樣,我無法測試它們,因此您可能會發現一些錯誤。
之前,我已經回答了類似的問題,並提供了一個可以正常工作的示例,我認為它確實可以滿足您的嘗試。 請參閱: 通過TCP連接傳輸屏幕截圖
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.