练习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. 20155229 2016-2007-2 《Java程序设计》第一周学习总结

    20155229 2016-2007-2 <Java程序设计>第一周学习总结 教材学习内容总结 1~18章的提问: 第一章:怎样撰写Java才不会沦于死背API文件.使用"复制. ...

  2. ruby学习笔记(1)-puts,p,print的区别

    ruby学习笔记-puts,p,print的区别 共同点:都是用来屏幕输出的. 不同点:puts 输出内容后,会自动换行(如果内容参数为空,则仅输出一个换行符号):另外如果内容参数中有转义符,输出时将 ...

  3. WPF中使用WindowChrome自定义窗口中遇到的最大化问题

    FrameWork 4.5 之后,内置了WindowChrome类,官方文档: https://msdn.microsoft.com/en-us/library/system.windows.shel ...

  4. 【转载】Direct3D纹理映射

    原文:Direct3D纹理映射 更详细的文章:DirectX中的纹理映射相关技术 (转)   创建纹理对象 1: HRESULT CreateTexture( 2:   UINT Width,//宽度 ...

  5. CSS深入理解absolute

    1.图片目标来覆盖,无依赖,真不赖: 2.如何定位下拉框,最佳实践来分享: 3.对其居中或边缘,定位实现有脸面: 4.星号时有时没有,破坏队形不用愁: 5.图文对其兼容差,绝对定位来开挂: 6.文字溢 ...

  6. 电信NB-IOT的温湿度采集器开发记录

    1. 首先打开浏览器,登录电信商用服务器,上传profile文件 2. 上传编解码插件在,注意的是,上传编解码插件是电信测试用服务器平台(不同的网址),反正不明白电信搞啥幺蛾子,得两个地方去上传 3. ...

  7. 欢迎使用 Flask¶

    欢迎使用 Flask¶ 欢迎阅读 Flask 文档. 本文档分为几个部分.我推荐您先从 安装 开始,之后再浏览 快速入门 章节. 教程 比快速入门更详细地介绍了如何用 Flask 创建一个完整的 应用 ...

  8. Electron小记

    一.安装 1.安装NodeJS 2.安装electronjs:npm install -g electron --unsafe-perm=true --allow-root 安装完,环境为: Node ...

  9. 一学就会pip换镜像源

    首先介绍一个国内好用的镜像站 阿里云 http://mirrors.aliyun.com/pypi/simple/ 豆瓣 http://pypi.douban.com/simple/ 清华大学 htt ...

  10. 【sed】常用命令

    替换 替换某一整行 sed '1c hello' test #将第一行替换为hello str1替换为str2 sed 's/^str1.*/str2/' filename #以str1开头 sed ...