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

    20155333 2016-2017-2 <Java程序设计>第三周学习总结 教材学习内容总结 第四章 类定义时使用class关键词,名称使用Clothes,建立实例要使用new关键词. ...

  2. DIV+CSS实现竖排按钮样式

    <div class="btn_left btn_left1">每日单元成功率</div><br/> <div class="b ...

  3. WPF中。。DataGrid 实现时间控件和下拉框控件

    DatePicker 和新的 DataGrid 行 用户与 DataGrid 中日期列的交互给我造成了很大的麻烦. 我通过将一个 Data Source 对象拖动到 WPF 窗口上,创建了一个 Dat ...

  4. day 3 模块

    1.系统自带模块  xxx.py 文件 就是模块 ### 模块存放位置 In [1]: import os In [2]: os.__file__ Out[2]: '/usr/lib/python3. ...

  5. P3368 【模板】树状数组 2(区间增减,单点查询)

    P3368 [模板]树状数组 2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表 ...

  6. windows下如何将Python文件打包成.exe可执行文件

    在使用Python做开发的时候,时不时会给自己编写了一些小工具辅助自己的工作,但是由于开发依赖环境问题,多数只能在自己电脑上运行,拿到其它电脑后就没法运行了.这显得很不方便,不符合我们的初衷,那么有没 ...

  7. 安装Vue.js的方法有三种

    1 使用独立的版本 在Vue.js官网上直接下载,在script标签里引用. 2 使用CND方法(不推荐) 3 NMP 方法 在用Vue.js构建大型应用的时候推荐使用NMP安装方法,NMP能很好的和 ...

  8. Python接口测试实战3(下)- unittest测试框架

    如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...

  9. JMeter:全面的乱码解决方案【转】

    本文是转自https://www.cnblogs.com/mawenqiangios/p/7918583.html 感谢分享者   中文乱码一直都是比较让人棘手的问题,我们在使用Jmeter的过程中, ...

  10. Java fluent风格(转载)

    转载:java Fluent风格 一.我们先写一个通常的,即不使用fluent风格 1.实体类 package com.xbq.demo.stu; /** * @ClassName: Student ...