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

    学号 2016-2017-2 <Java程序设计>第2周学习总结 教材学习内容总结 CH3中是讲Java中的基本语法知识,有些语法与C语言类似而有些则不太相同. C语言有着很多的基本类型如 ...

  2. 20155310 2016-2017-2 《Java程序设计》第九周学习总结

    20155310 2016-2017-2 <Java程序设计>第九周学习总结 教材学习内容总结 JDBC入门 •数据库本身是个独立运行的应用程序 •撰写应用程序是利用通信协议对数据库进行指 ...

  3. dedecms 后台网站 标题设置

    打开文件夹,找到dede/templets/index2.htm,修改第6行就行了

  4. GridView中加入//实现分页

    要在GridView中加入//实现分页 AllowPaging="true" PageSize="10" // 分页时触发的事件 protectedvoid g ...

  5. [BZOJ1857][SCOI2010]传送带-[三分]

    Description 传送门 Solution 三分套三分.代码简单但是证明苦兮兮.. 假如我们在AB上选了一个点G,求到该点到D的最小时间. 图中b与CD垂直.设目前从G到D所耗时间最短的路径为G ...

  6. Yii2 模块module笔记

    包含内容: 使用GII新建module 建立子模块 在其他控制器中调用模块的操作(action) 1. 使用Gii工具新建module 注意模块的路径,我们没有写backend\modules\Art ...

  7. pycharm设置github

    1.打开file,选择settings,找到Version Contorl,打开找到GitHub ,HOST填github.com,用户名,密码,test,稍等一会,会提示成功 2. 设置好以后 打开 ...

  8. idea css文件不识别的问题的解决方案

    可以看到 progressBar不识别 发现仅仅是这一个文件名不识别 所以换一个任意别的文件名即可识别

  9. Java的安装与配置

    安装JAVA 下载JAVA JDK安装包,JDK是Java Development Kit的缩写,即开发工具包,里面包含了平时用户用到的JRE,也就是Java Runtime Enviroment运行 ...

  10. Android手机测试-ddms&monitor-抓crash,log

    1.安装adb offline解决办法: 原因就是android 4.2以上的版本过高,sdk的adb驱动不匹配,需要升级.我原本的adb是1.0.29,升级为1.0.31,问题就解决了. 2.安装s ...