先谈需求,本demo源于实验室的师兄们找工作的时候,针对有些公司会监视多屏幕的情况,突发奇想自己写了一个小demo来分享屏幕,随手写的使用价值不大~在本机测试效果不错,但是跨机效果很一般,不知道是不是路由器的问题。另没有对接收发送的数据进行校验,只是比较基础的实现。为什么说是局域网,因为数据传输效果太糟糕,理论远程也是可以的,没有试。只贴出了处理代码,界面代码和编译后的结果我上传github了,可以查看
服务器代码:
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
using System.Drawing;
using System.IO;
namespace screen_server
{
class Server
{
private string localIP;
private Bitmap screenNow;
private string[] terminalList;
private int listenPort;
private int screenHeight;
private int screenWidth;
private bool isWork;
private byte[] buffer;
private string errorMessage;
private Socket server;
public Server(int listenPort)
{
screenWidth = Screen.PrimaryScreen.Bounds.Width;
screenHeight = Screen.PrimaryScreen.Bounds.Height;
ScreenNow = new Bitmap(screenWidth, screenHeight);
IsWork = false;
this.listenPort = listenPort;
//获取本地ip地址
try
{
string HostName = Dns.GetHostName(); //得到主机名
IPHostEntry IpEntry = Dns.GetHostEntry(HostName);
for (int i = 0; i < IpEntry.AddressList.Length; i++)
{
if (IpEntry.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
{
//限制了实验室网段或者学校内网
if (IpEntry.AddressList[i].ToString().Contains("192.168.199") || IpEntry.AddressList[i].ToString().Contains("114.213"))
{
LocalIP = IpEntry.AddressList[i].ToString();
break;
}
}
}
if (LocalIP == null)
LocalIP = "";
}
catch (Exception ex)
{
errorMessage = ex.Message;
showErrorMessage();
}
}
public string[] TerminalList { get => terminalList; set => terminalList = value; }
public string LocalIP { get => localIP; set => localIP = value; }
public Bitmap ScreenNow { get => screenNow; set => screenNow = value; }
public bool IsWork { get => isWork; set => isWork = value; }
public void showErrorMessage()
{
}
public void startService()
{
server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse(LocalIP);
server.Bind(new IPEndPoint(ip, listenPort));
server.Listen(10);
Thread myThread = new Thread(ListenClientConnect);
myThread.Start();
Thread catchScreen = new Thread(screenUpdate);
catchScreen.Start();
IsWork = true;
}
private void ListenClientConnect()
{
while (true)
{
Socket client = server.Accept();
Thread sendThread = new Thread(sendPic);
sendThread.Start(client);
}
}
private void screenUpdate()
{
Bitmap temp = new Bitmap(screenWidth, screenHeight);
Graphics gc = Graphics.FromImage(temp);
while (true)
{
gc.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(screenWidth, screenHeight));
imgtoBytes(temp);
screenNow = new Bitmap(temp);
GC.Collect();
Thread.Sleep(500);
}
}
private void imgtoBytes(Bitmap bitmap)
{
MemoryStream ms = new MemoryStream();
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
buffer = ms.GetBuffer();
ms.Close();
}
private void sendPic(object clientSocket)
{
Socket client = (Socket)clientSocket;
byte[] receiveBuffer = new byte[1024];
byte[] imageCopy;
while (true)
{
try
{
//客户端返回确认后才发送新的数据
int receiveLength = client.Receive(receiveBuffer);
imageCopy = new byte[buffer.Length];
Buffer.BlockCopy(buffer, 0, imageCopy, 0, buffer.Length);
byte[] dataLength = BitConverter.GetBytes(imageCopy.Length);
client.Send(dataLength);
receiveLength = client.Receive(receiveBuffer);
client.Send(imageCopy);
}
catch
{
//do Nothing,just break
}
}
}
}
}
客户端代码:
using System;
using System.Drawing;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
namespace screenClient
{
public partial class clientWin : Form
{
public clientWin()
{
InitializeComponent();
}
private void startButton_Click(object sender, EventArgs e)
{
string ipPort = configBox.Text;
string[] config = ipPort.Split(':');
if (config.Length!=2)
{
MessageBox.Show("请输入正确的ip和端口号!");
return;
}
string IP = config[0];
int port = Convert.ToInt32(config[1]);
try
{
IPAddress ip = IPAddress.Parse(IP);
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientSocket.Connect(new IPEndPoint(ip, port));
Thread imageUpdate = new Thread(update);
imageUpdate.Start(clientSocket);
}
catch (Exception ex)
{
MessageBox.Show("建立连接失败,请重试!");
}
}
private void update(object clientSocket)
{
Socket client = (Socket)clientSocket;
int receiveNumber;
byte[] buffer;
byte[] image;
while (true)
{
//先发送一个确认连接包
buffer = new byte[1];
buffer[0] = 1;
client.Send(buffer);
//先记录数据的大小,再申请对应大小的缓冲区
buffer = new byte[4];
receiveNumber = client.Receive(buffer);
int dataLength = BitConverter.ToInt32(buffer, 0);
client.Send(buffer);
buffer = new byte[4096];
image = new byte[dataLength];
GC.Collect();
int offset = 0;
while (offset != dataLength)
{
receiveNumber = client.Receive(buffer);
Buffer.BlockCopy(buffer, 0, image, offset, receiveNumber);
offset += receiveNumber;
}
pictureBox.Image = getBitmap(image);
}
}
private Bitmap getBitmap(byte[] bytesData)
{
MemoryStream ms1 = new MemoryStream(bytesData);
Bitmap bm = (Bitmap)Image.FromStream(ms1);
ms1.Close();
return bm;
}
}
}
使用方式:
首先打开服务器端,填入端口号(建议10000~65534),然后点击监听端口按钮(这个时候会给出本机ip,但我限定了局域网192.168.199和114.213前缀,可自行查询ip或者修改代码),再启动服务即可。提供了浏览功能~客户端填入ip地址和端口号即可。