练习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. 20155213 实验三《敏捷开发与XP实践》实验报告

    20155213 实验三<敏捷开发与XP实践>实验报告 实验内容 XP基础 XP核心实践 相关工具 实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)> ...

  2. 20155229实验三 《Java面向对象程序设计实验三 敏捷开发与XP实践 》实验报告

    实验题目 1.在IDEA中使用工具(Code->Reformate Code)把下面代码重新格式化,再研究一下Code菜单,找出一项让自己感觉最好用的功能. 2.下载搭档实验二的Complex代 ...

  3. Android开发——LinearLayout和RelativeLayout的性能对比

    0. 前言 我们都知道新建一个Android项目自动生成的Xml布局文件的根节点默认是RelativeLayout,这不是IDE默认设置,而是由android-sdk\tools\templates\ ...

  4. 【转载】从零实现3D图像引擎:(1)环境配置与项目框架

    原文:从零实现3D图像引擎:(1)环境配置与项目框架 0. 要学懂3D程序设计,必然要精通3D相关的线性代数.3D几何.复分析等相关知识,我也因为如此才开始这个博客系列的写作,不自己实现,就不是自己的 ...

  5. 【LG5017】[NOIP2018pj]摆渡车

    [LG5017][NOIP2018pj]摆渡车 题面 洛谷 题解 震惊!普及组竟然考斜率优化??? 当然有其他的方法 首先我们转化一下模型 此题可以变为: 在一根时间轴上有一些点,每个时间点\(i\) ...

  6. sklearn半监督学习

    标签: 半监督学习 作者:炼己者 欢迎大家访问 我的简书 以及 我的博客 本博客所有内容以学习.研究和分享为主,如需转载,请联系本人,标明作者和出处,并且是非商业用途,谢谢! --- 摘要:半监督学习 ...

  7. javaweb(十五)——JSP基础语法

    任何语言都有自己的语法,JAVA中有,JSP虽然是在JAVA上的一种应用,但是依然有其自己扩充的语法,而且在JSP中,所有的JAVA语句都可以使用. 一.JSP模版元素 JSP页面中的HTML内容称之 ...

  8. HTML5 + CSS3 实现地球绕太阳公转

    使用的是正面视角,主要是用 HTML5 + CSS3 来实现,JS只是用来画图. test.html: <!DOCTYPE html> <html> <head> ...

  9. Vue学习计划基础笔记(四) - 事件处理

    事件处理 目标: 熟练掌握事件监听的方式,熟悉事件处理方式以及各类事件修饰符 理解在html中监听事件的意义 监听事件(v-on) 类似普通的on,例如v-on:click或@click就相当于普通的 ...

  10. Saving James Bond - Easy Version (MOOC)

    06-图2 Saving James Bond - Easy Version (25 分) This time let us consider the situation in the movie & ...