练习Socket传文件,先添加一个组件,简化socket发送和接收文件,

获取IP和端口的类

    public static class AddressHelper
{
/// <summary>
/// 获取本机IPv4地址的集合
/// </summary>
/// <returns></returns>
public static IPAddress[] GetLocalhostIPv4Addresses()
{
String LocalhostName = Dns.GetHostName(); IPHostEntry host = Dns.GetHostEntry(LocalhostName);
List<IPAddress> addresses=new List<IPAddress>();
foreach (IPAddress ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
addresses.Add(ip);
}
return addresses.ToArray();
} /// <summary>
/// 以交互方式生成有效的远程主机访问终结点,适用于控制台程序
/// </summary>
/// <returns></returns>
public static IPEndPoint GetRemoteMachineIPEndPoint()
{
IPEndPoint iep = null;
try
{
Console.Write("请输入远程主机的IP地址:");
IPAddress address = IPAddress.Parse(Console.ReadLine());
Console.Write("请输入远程主机打开的端口号:");
int port = Convert.ToInt32(Console.ReadLine());
if (port > || port < )
throw new Exception("端口号应该为[1024,65535]范围内的整数");
iep = new IPEndPoint(address, port); }
catch (ArgumentNullException)
{
Console.WriteLine("输入的数据有误!");
}
catch (FormatException)
{
Console.WriteLine("输入的数据有误!");
} catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return iep;
} /// <summary>
/// 获取本机当前可用的端口号,此方法是线程安全的
/// </summary>
/// <returns></returns>
public static int GetOneAvailablePortInLocalhost()
{
Mutex mtx = new Mutex(false, "MyNetworkLibrary.AddressHelper.GetOneAvailablePort");
try
{
mtx.WaitOne();
IPEndPoint ep = new IPEndPoint(IPAddress.Any, );
using (Socket tempSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
tempSocket.Bind(ep);
IPEndPoint ipep = tempSocket.LocalEndPoint as IPEndPoint;
return ipep.Port;
}
}
finally
{
mtx.ReleaseMutex();
}
}
}

socket发送和接收二进制

 public static class SocketHelper
{
/// <summary>
/// 接收变长的数据,要求其打头的4个字节代表有效数据的长度
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static byte[] ReceiveVarData(Socket s)
{
if (s == null)
throw new ArgumentNullException("s");
int total = ; //已接收的字节数
int recv;
//接收4个字节,得到“消息长度”
byte[] datasize = new byte[];
recv = s.Receive(datasize, , , );
int size = BitConverter.ToInt32(datasize, );
//按消息长度接收数据
int dataleft = size;
byte[] data = new byte[size];
while (total < size)
{
recv = s.Receive(data, total, dataleft, );
if (recv == )
{
break;
}
total += recv;
dataleft -= recv;
}
return data;
} /// <summary>
/// 发送变长的数据,将数据长度附加于数据开头
/// </summary>
/// <param name="s"></param>
/// <param name="data"></param>
/// <returns></returns>
public static int SendVarData(Socket s, byte[] data)
{
int total = ;
int size = data.Length; //要发送的消息长度
int dataleft = size; //剩余的消息
int sent;
//将消息长度(int类型)的,转为字节数组
byte[] datasize = BitConverter.GetBytes(size);
//将消息长度发送出去
sent = s.Send(datasize);
//发送消息剩余的部分
while (total < size)
{
sent = s.Send(data, total, dataleft, SocketFlags.None);
total += sent;
dataleft -= sent;
}
return total;
}
}

好,现在开始制作socket,界面使用WPF

代码:

   public partial class MainWindow : Window
{
Socket server = null;
string picPath = "";
public MainWindow()
{
InitializeComponent();
Init();
} private void Init()
{
//初始化
var ip = AddressHelper.GetLocalhostIPv4Addresses().First();
var port = AddressHelper.GetOneAvailablePortInLocalhost();
txtIp.Text = ip.ToString();
txtPort.Text = port.ToString(); IPEndPoint iep = new IPEndPoint(ip, port);
server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server.Bind(iep);
server.Listen();
//启动线程开始接收数据
DoWork();
tbinfo.Text = iep.ToString() + "已启动监听";
} private Task DoWork()
{
return Task.Run(() =>
{
//创建委托,更新图片控件
Action<byte[]> action = buf =>
{
img.Source = ByteToBitmapImage(buf);
};
while (true)
{
var client = server.Accept();
var data = SocketHelper.ReceiveVarData(client); this.Dispatcher.BeginInvoke(action, data);
client.Shutdown(SocketShutdown.Both);
client.Close();
}
}); }
//二进制转图片
public BitmapImage ByteToBitmapImage(byte[] buf)
{
BitmapImage bmp = new BitmapImage();
MemoryStream ms = new MemoryStream(buf);
ms.Position = ;
bmp.BeginInit();
bmp.StreamSource = ms;
bmp.EndInit();
return bmp;
}
//选择图片
private void Button_Click(object sender, RoutedEventArgs e)
{
System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog();
if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
picPath = ofd.FileName;
img.Source = new BitmapImage(new Uri(picPath));
}
}
//取远程终端的IPEndPoint
private IPEndPoint getRemIEP()
{
return new IPEndPoint(IPAddress.Parse(txtIp.Text), int.Parse(txtPort.Text));
}
//发送
private void Button_Click_1(object sender, RoutedEventArgs e)
{
var newSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
using (newSocket)
{
IPEndPoint remIep = getRemIEP();
newSocket.Connect(remIep);
var buf = File.ReadAllBytes(picPath);
SocketHelper.SendVarData(newSocket, buf);
}
}
}

上面代码要添加两个引用,一个是System.Windows.Forms,另一个就是最上面所建的类,这时可以打开两个应用,在端口处输入远程的端口,相互就可以发送图片,并能显示图片,如下图

相互传输使用二进制传输,文件转二进制,使用File.ReadAllBytes方法可方便转换成二进制。

上面只是简单的实现了传输图片的代码,实现中应加入错误判断等异常处理。

Socket 传一幅图片给另一个终端的更多相关文章

  1. socket传数据并记录到文件中

    最近在新项目中要通过socket传一些数据,下面是程序: 功能: 将客户端发送的json数据写入到日志文件中,如果数据不是json的,丢弃. 程序如下: #!/usr/bin/env python # ...

  2. python socket编程---从使用Python开发一个Socket示例说到开发者的思维和习惯问题

    今天主要说的是一个开发者的思维和习惯问题. 思维包括编程的思维和解决一个具体问题的分析思维,分析思路,分析方法,甚至是分析工具. 无论是好习惯还是不好的习惯,都是在者一天一天的思维中形成的.那些不好的 ...

  3. 抱歉,您必须拥有一个终端来执行 sudo

    Linux ssh执行远端服务器sudo命令时有如下报错: sudo: sorry, you must have a tty to run sudo sudo:抱歉,您必须拥有一个终端来执行 sudo ...

  4. crontab不能执行sudo:抱歉,您必须拥有一个终端来执行 sudo

    最近做一个可执行shell调度的需求,要求用户输入shell,然后后台定时调度运行.实现大致为:保存用户的输入,设定时间,crontab定时执行用户的输入.但这里涉及到一个安全问题,如何确定用户的输入 ...

  5. export的变量另开一个终端失效解决方法

    有时候,我们需要把一个export的变量全局话,否则每开一个终端又需要重新export,很是麻烦 首先直接export某个变量的话就只能在当前子终端生效,另开一个终端就失效了 如果修改.bash_pr ...

  6. sudo:抱歉,您必须拥有一个终端来执行 sudo 解决办法;ssh执行sudo命令的方法;给用户增加sudo免密权限

    1.supervisor使用sudo执行命令的时候,报错 2.解决办法: 编辑 /etc/sudoers 文件,将Default requiretty注释掉. sudo vim /etc/sudoer ...

  7. ubuntu打开终端多开标签的快捷键是ctrl+ shift+ T 对比ctrl+ alt+ T 另外窗口打开一个终端

    ubuntu打开终端多开标签的快捷键是ctrl+ shift+ T 对比ctrl+ alt+ T 另外窗口打开一个终端

  8. 使用fuser命令kill一个终端(特殊文件)的方法

    /*********************************************************************  * Author  : Samson  * Date   ...

  9. 利用socket编程在ESP32上搭建一个TCP客户端

    通过之前http://www.cnblogs.com/noticeable/p/7636582.html中对socket的编程,已经可以知道如何通过socket编程搭建服务器和客户端了,现在,就在ES ...

随机推荐

  1. 20155325 信息安全技术 实验二 Windows口令破解

    内容一览 实验结果 遇到的问题 思考题 详细步骤与解析(为了使存做笔记资料而做) 实验结果 字典破解 暴力破解 -不同密码强度的破解时间比较 用户名 密码 破解方式 破解时间 TEST (年月日) 字 ...

  2. C语言学习笔记1

    C语言假期学习笔记1 关于吃回车问题 第一个解决方案是使用ch=getchar(); 第二个方案是在scanf(" %c",&b):在%c加空格,将存于缓冲区的回车符读入 ...

  3. XAMPP设置tomcat自启动时,报无效的Win32程序

    最近给一个客户开发了一套系统,需要在内网中部署.系统是Java + Tomcat7 + mysql开发的. 考虑到客户内网不能上网的情况下,想使用XAMPP的便捷性,给客户进行部署.因为只需要Tomc ...

  4. 在Centos7下安装与部署.net core

    在Centos7下安装与部署.net core 2018年02月28日 19:36:16 阅读数:388 个人安装流程,参照文档 https://www.cnblogs.com/Burt/p/6566 ...

  5. autoreleasepool 自动释放池的理解

    常见的面试题:以下代码存在什么样的问题?应该如何改进? for (int i = 0; i < 100000; i++) { NSString *str = @"abc"; ...

  6. 【jQuery学习】用JavaScript写一个输出多选框的个数报错:Cannot set property 'onclick' of null"

    说明:代码段来源于:<锋利的jQuery> 根据代码段我补充的代码如下: <!DOCTYPE html> <html> <head> <meta ...

  7. 探究linux设备驱动模型之——platform虚拟总线(二)

    上回说到,platform_match是驱动和设备之间的媒人婆,那么platform_match是如何匹配驱动和设备的呢?platform总线定义的匹配条件很简单,主要就是查看驱动结构体和设备结构体的 ...

  8. php实现图形计算器

    存档: index.php <html> <head> <title>图形计算器开发</title> <meta http-equiv=" ...

  9. ubuntu apt-xxx

    1. apt-get install xxx 2. dpkg -l ; list software already installed. 3. apt-cache dumpavail ; print ...

  10. html表单总结

    总结了下html表单: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...