写点什么

一个简单的 socket 小工具

作者:为自己带盐
  • 2021 年 12 月 18 日
  • 本文字数:2839 字

    阅读完需:约 9 分钟

这个也是搬运的之前博客的内容,感觉沉淀总结的还不够,近期真的太忙了。。

背景

记得彼时彼刻,我们有一个需求,就是要不定期的把一些本地资源拷贝到附件服务器,拷贝的方式,就是手工操作。

后来我实在是嫌麻烦,就写了个小工具,在一定程度上提高了工作效率。

思路

当时做这个工具,思路也很简单。

1.在服务器的后台跑一个程序,监听一个 http 端口;

2.每次需要传输文件的时候,客户端先向服务端发送一条消息;

3.服务端收到消息后,会响应客户端,收到可以传输的响应信号后,就可以开始传输文件了。

4.服务端解压缩(可选)

因为我们当时传输的文件是要打包并分片传输的,因为特别零散,不打包直接传的话,时间太长,而打包的话,服务端的程序就需要具备解压缩的能力。

代码

/// <summary>/// 发送数据包/// </summary>/// <param name="s"></param>/// <param name="data"></param>/// <returns></returns>public static int SendVarData(Socket s, byte[] data){    int total = 0;    int size = data.Length;    int dataleft = size;    int sent;    byte[] datasize = new byte[4];
try { 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; } catch { return 3;
}}/// <summary>/// 接受数据包/// </summary>/// <param name="s"></param>/// <returns></returns>public static byte[] ReceiveVarData(Socket s){ int total = 0; int recv; byte[] datasize = new byte[4]; recv = s.Receive(datasize, 0, 4, SocketFlags.None); int size = BitConverter.ToInt32(datasize, 0); int dataleft = size; byte[] data = new byte[size]; while (total < size) { recv = s.Receive(data, total, dataleft, SocketFlags.None); if (recv == 0) { data = null; break; } total += recv; dataleft -= recv; } return data;}/// <summary>/// 发送文件/// </summary>/// <param name="s"></param>/// <returns></returns>public static bool SendFile(string IP, int Port, string fullPath){ //创建一个文件对象 FileInfo EzoneFile = new FileInfo(fullPath); //打开文件流 FileStream EzoneStream = EzoneFile.OpenRead(); //包的大小 int PacketSize = 10000; //包的数量 int PacketCount = (int)(EzoneStream.Length / ((long)PacketSize)); //最后一个包的大小 int LastDataPacket = (int)(EzoneStream.Length - ((long)(PacketSize * PacketCount))); //指向远程服务端节点 IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(IP), Port); //创建套接字 Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //连接到发送端 try { client.Connect(ipep); Common.ConsoleM("connect...ok!"); } catch { Common.ConsoleM("连接服务器失败!"); return false; } //获得客户端节点对象 IPEndPoint clientep = (IPEndPoint)client.RemoteEndPoint; //发送[文件名]到客户端 TransferFiles.SendVarData(client, System.Text.Encoding.Unicode.GetBytes("F_" + EzoneFile.Name)); //发送[包的大小]到客户端 TransferFiles.SendVarData(client, System.Text.Encoding.Unicode.GetBytes(PacketSize.ToString())); //发送[包的总数量]到客户端 TransferFiles.SendVarData(client, System.Text.Encoding.Unicode.GetBytes(PacketCount.ToString())); //发送[最后一个包的大小]到客户端 TransferFiles.SendVarData(client, System.Text.Encoding.Unicode.GetBytes(LastDataPacket.ToString())); bool isCut = false; //数据包 byte[] data = new byte[PacketSize]; int cnt = 0; //开始循环发送数据包 for (int i = 0; i < PacketCount; i++) { //从文件流读取数据并填充数据包 EzoneStream.Read(data, 0, data.Length); //发送数据包 if (TransferFiles.SendVarData(client, data) == 3) { isCut = true; return false; } System.Threading.Thread.Sleep(100); Console.WriteLine(" "); Console.SetCursorPosition(0, Console.CursorTop - 1); float percent = i * 100 / PacketCount; cnt = i; Console.Write(DateTime.Now + "-已发送" + cnt + "个包,共有" + PacketCount + "个包"); } //如果还有多余的数据包,则应该发送完毕! if (LastDataPacket != 0) { data = new byte[LastDataPacket]; EzoneStream.Read(data, 0, data.Length); TransferFiles.SendVarData(client, data); } if (cnt < PacketCount) { Console.WriteLine(""); Common.ConsoleM("余量包发送完毕,共计发送" + PacketCount + "个数据包"); } //关闭套接字 client.Close(); //关闭文件流 EzoneStream.Close(); if (!isCut) { return true; } return false;}/// <summary>/// 发送消息/// </summary>/// <param name="s"></param>/// <returns></returns>public static bool SendMsg(string IP, int Port, string Msg){ //指向远程服务端节点 IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(IP), Port); //创建套接字 Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //连接到发送端 try { client.Connect(ipep); //Common.ConsoleM("connect...ok!"); TransferFiles.SendVarData(client, System.Text.Encoding.Unicode.GetBytes(Msg)); while (true) { string ret = System.Text.Encoding.Unicode.GetString(TransferFiles.ReceiveVarData(client)); if (!string.IsNullOrEmpty(ret)) { Common.ConsoleM(ret); break; } } } catch { Common.ConsoleM("连接服务器失败!"); return false; } return true;}
复制代码

好了大概就是这个样子,至于客户端和服务端交互上,我就不贴代码了,非常简单,而且我写的风格也没啥参考价值,最多就是多了一个思路,大家完全可以自己改造。完整代码在这→https://gitee.com/Tony_df/SocketProject

最后的效果是这样







因为是内部使用,所以就做成了控制台程序,并且自定义了几个命令参数,然后还可以通过批处理文件来快速启动客户端


用户头像

学着码代码,学着码人生。 2019.04.11 加入

狂奔的小码农

评论

发布
暂无评论
一个简单的socket小工具