C# 简单通信(实现文件传输)
https://blog.csdn.net/Sayesan/article/details/82185772
之前写过一个简单通信传输,不过只有聊天的功能,现在实现了文件传输的功能,借鉴于网上一篇博客,不过他写的仅仅是客户端对于服务器发送文件,我稍微优化了这个功能,实现了,端与端之间信息的互发和文件的互发,感觉学习这些新的东西,还刚开始,进度很慢,很多东西都需要从新去学习,不过慢慢来!Fighting!!!
服务器:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
namespace EasyChat
{
public partial class Server : Form
{
public Server()
{
InitializeComponent();
//关闭对文本框的非法线程操作检查
TextBox.CheckForIllegalCrossThreadCalls = false;
}
private void Server_Load(object sender, EventArgs e)
{
textIP.AppendText("127.0.0.1");
textPORT.AppendText("5555");
}
Thread threadWatch = null;
Socket socketWatch = null;
private void ServerBegin_Click(object sender, EventArgs e)
{
//定义一个套接字,监听发来的信息,包含3个参数(IP4寻址协议,流式连接,TCP协议)
socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
int port = Convert.ToInt32(textPORT.Text.Trim());
IPAddress ip = IPAddress.Parse(textIP.Text.Trim());
//绑定IP地址和端口号
IPEndPoint ipe = new IPEndPoint(ip, port);
socketWatch.Bind(ipe);
socketWatch.Listen(20);//监听队列长度,20
//负责监听的线程
threadWatch = new Thread(WatchConnect);
//。。。
threadWatch.IsBackground = true;
threadWatch.Start();
Message.AppendText("服务器已经启动,开始监听..."+"\r\n");
}
Socket socketConnect = null;
private void WatchConnect()
{
while (true)
{
try
{
socketConnect = socketWatch.Accept();
}
catch (Exception ex)
{
Message.AppendText(ex.Message);
break;
}
Message.AppendText("客户端连接成功,可以开始通信..."+"\r\n");
//创建通信线程,感觉这个和Thread的区别,就是这个有参,另一个无参
ParameterizedThreadStart pts = new ParameterizedThreadStart(ServerRec);
Thread thr = new Thread(pts);
thr.Start(socketConnect);
}
}
string recStr = null;
private void ServerRec(object obj)
{
Socket socketServer = obj as Socket;
long fileLength = 0;
while (true)
{
int firstRcv = 0;
byte[] buffer = new byte[8 * 1024];
try
{
//获取接受数据的长度,存入内存缓冲区,返回一个字节数组的长度
if (socketServer != null) firstRcv = socketServer.Receive(buffer);
if (firstRcv > 0)//大于0,说明有东西传过来
{
if (buffer[0] == 0)//0对应文字信息
{
recStr = Encoding.UTF8.GetString(buffer, 1, firstRcv - 1);
Message.AppendText("ZXY: " + GetTime() + "\r\n" + recStr + "\r\n");
}
if (buffer[0] == 1)//1对应文件信息
{
string filenameSuffix = recStr.Substring(recStr.LastIndexOf("."));
SaveFileDialog sfDialog = new SaveFileDialog()
{
Filter = "(*" + filenameSuffix + ")|*" + filenameSuffix + "",
FileName = recStr
};
if (sfDialog.ShowDialog(this) == DialogResult.OK)
{
string savePath = sfDialog.FileName;
int rec = 0;
long recFileLength = 0;
bool firstWrite = true;
using (FileStream fs = new FileStream(savePath, FileMode.Create, FileAccess.Write))
{
while (recFileLength < fileLength)
{
if (firstWrite)
{
fs.Write(buffer, 1, firstRcv - 1);
fs.Flush();
recFileLength += firstRcv - 1;
firstWrite = false;
}
else
{
rec = socketServer.Receive(buffer);
fs.Write(buffer, 0, rec);
fs.Flush();
recFileLength += rec;
}
}
fs.Close();
}
string fName = savePath.Substring(savePath.LastIndexOf("\\") + 1);
string fPath = savePath.Substring(0, savePath.LastIndexOf("\\"));
Message.AppendText("ZXY: " + GetTime() + "\r\n你成功接收了文件..." + fName + "\r\n保存路径为:" + fPath + "\r\n");
}
}
if (buffer[0] == 2)//2对应文件名字和长度
{
string fileNameWithLength = Encoding.UTF8.GetString(buffer, 1, firstRcv - 1);
recStr = fileNameWithLength.Split('-').First();
fileLength = Convert.ToInt64(fileNameWithLength.Split('-').Last());
}
}
}
catch (Exception ex)
{
Message.AppendText("系统异常..." + ex.Message);
break;
}
}
}
private void ServerSend(string SendStr,byte symbol)
{
//用UTF8能接受文字信息
byte[] buffer = Encoding.UTF8.GetBytes(SendStr);
//实际发送的字节数组比实际输入的长度多1,用于存取标识符
byte[] newBuffer = new byte[buffer.Length+1];
//标识符添加在位置为0的地方
newBuffer[0] = symbol;
Buffer.BlockCopy(buffer,0,newBuffer,1,buffer.Length);
socketConnect.Send(newBuffer);
Message.AppendText("PYT: "+ GetTime() + "\r\n" + SendStr+"\r\n");
}
string filePath = null;
string fileName = null;
private void Select_Click(object sender, EventArgs e)
{
OpenFileDialog ofDialog = new OpenFileDialog();
if(ofDialog.ShowDialog(this) == DialogResult.OK)
{
fileName = ofDialog.SafeFileName;//获取选取文件的文件名
File.Text = fileName;//将文件名显示在文本框上
filePath = ofDialog.FileName;//获取包含文件名的全路径
}
}
private void SendFile(string fileFullPath)
{
if (string.IsNullOrEmpty(fileFullPath))
{
MessageBox.Show(@"请选择需要发送的文件!");
return;
}
//发送文件前,将文件名和长度发过去
long fileLength = new FileInfo(fileFullPath).Length;
string totalMsg = string.Format("{0}-{1}", fileName, fileLength);
ServerSend(totalMsg, 2);
byte[] buffer = new byte[8*1024];
using (FileStream fs = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
{
int readLength = 0;
bool firstRead = true;
long sentFileLength = 0;
while ((readLength = fs.Read(buffer, 0, buffer.Length)) > 0 && sentFileLength < fileLength)
{
sentFileLength += readLength;
//第一次发送的字节流上加个前缀1
if (firstRead)
{
byte[] firstBuffer = new byte[readLength + 1];
//标记1,代表为文件
firstBuffer[0] = 1;
Buffer.BlockCopy(buffer, 0, firstBuffer, 1, readLength);
socketConnect.Send(firstBuffer, 0, readLength + 1, SocketFlags.None);
firstRead = false;
continue;
}
socketConnect.Send(buffer, 0, readLength, SocketFlags.None);
}
fs.Close();
}
Message.AppendText("SoFlash:" + GetTime() + "\r\n您发送了文件:" + fileName + "\r\n");
}
private void Send_Click(object sender, EventArgs e)
{
ServerSend(SendMsg.Text,0);
}
private void SendMsg_keyDown(object sender, KeyEventArgs e)//Enter发送
{
if (e.KeyCode == Keys.Enter)
{
ServerSend(SendMsg.Text,0);
}
}
private void Sendfile_Click(object sender, EventArgs e)
{
SendFile(filePath);
}
public DateTime GetTime()//获取系统时间
{
DateTime now = new DateTime();
now = DateTime.Now;
return now;
}
}
}
客户端:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
namespace EasyChats
{
public partial class Client : Form
{
public Client()
{
InitializeComponent();
TextBox.CheckForIllegalCrossThreadCalls = false;
}
private void Client_Load(object sender, EventArgs e)
{
textIP.AppendText("127.0.0.1");
textPort.AppendText("5555");
}
Socket socketClient = null;
Thread threadClient = null;
private void BeginClient_Click(object sender, EventArgs e)
{
socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
int port = Convert.ToInt32(textPort.Text.Trim());
IPAddress ip = IPAddress.Parse(textIP.Text.Trim());
IPEndPoint ipe = new IPEndPoint(ip, port);
socketClient.Connect(ipe);
threadClient = new Thread(RecMsg);
threadClient.IsBackground = true;
threadClient.Start();
Message.AppendText("已经与服务端建立连接,可以开始通信...\r\n");
}
private void RecMsg()
{
long fileLength = 0;
string recStr = null;
while (true)
{
int firstRcv = 0;
byte[] buffer = new byte[8 * 1024];
try
{
if (socketClient != null) firstRcv = socketClient.Receive(buffer);
if (firstRcv > 0)
{
if (buffer[0] == 0)
{
recStr = Encoding.UTF8.GetString(buffer, 1, firstRcv - 1);
Message.AppendText("PYT: " + GetTime() + "\r\n" + recStr + "\r\n");
}
if (buffer[0] == 1)
{
string filenameSuffix = recStr.Substring(recStr.LastIndexOf("."));
SaveFileDialog sfDialog = new SaveFileDialog()
{
Filter = "(*" + filenameSuffix + ")|*" + filenameSuffix + "",
FileName = recStr
};
if (sfDialog.ShowDialog(this) == DialogResult.OK)
{
string savePath = sfDialog.FileName;
int rec = 0;
long recFileLength = 0;
bool firstWrite = true;
using (FileStream fs = new FileStream(savePath, FileMode.Create, FileAccess.Write))
{
while (recFileLength < fileLength)
{
if (firstWrite)
{
fs.Write(buffer, 1, firstRcv - 1);
fs.Flush();
recFileLength += firstRcv - 1;
firstWrite = false;
}
else
{
rec = socketClient.Receive(buffer);
fs.Write(buffer, 0, rec);
fs.Flush();
recFileLength += rec;
}
}
fs.Close();
}
string fName = savePath.Substring(savePath.LastIndexOf("\\") + 1);
string fPath = savePath.Substring(0, savePath.LastIndexOf("\\"));
Message.AppendText("ZXY: " + GetTime() + "\r\n你成功接收了文件..." + fName + "\r\n保存路径为:" + fPath + "\r\n");
}
}
if (buffer[0] == 2)
{
string fileNameWithLength = Encoding.UTF8.GetString(buffer, 1, firstRcv - 1);
recStr = fileNameWithLength.Split('-').First();
fileLength = Convert.ToInt64(fileNameWithLength.Split('-').Last());
}
}
}
catch (Exception ex)
{
Message.AppendText("系统异常..." + ex.Message);
break;
}
}
}
private void ClientSend(string SendStr, byte symbol)
{
byte[] buffer = Encoding.UTF8.GetBytes(SendStr);
byte[] newBuffer = new byte[buffer.Length + 1];
newBuffer[0] = symbol;
Buffer.BlockCopy(buffer, 0, newBuffer, 1, buffer.Length);
socketClient.Send(newBuffer);
Message.AppendText("ZXY: " + GetTime() + "\r\n" + SendStr + "\r\n");
}
private void Send_Click_1(object sender, EventArgs e)
{
ClientSend(SendMsg.Text, 0);
}
string filePath = null;
string fileName = null;
private void fileSelect_Click(object sender, EventArgs e)
{
OpenFileDialog ofDialog = new OpenFileDialog();
if (ofDialog.ShowDialog(this) == DialogResult.OK)
{
fileName = ofDialog.SafeFileName;
FileName.Text = fileName;
filePath = ofDialog.FileName;
}
}
private void fileSend_Click(object sender, EventArgs e)
{
SendFile(filePath);
}
private void SendFile(string fileFullPath)
{
if (string.IsNullOrEmpty(fileFullPath))
{
MessageBox.Show(@"请选择需要发送的文件...");
return;
}
long fileLength = new FileInfo(fileFullPath).Length;
string totalMsg = string.Format("{0}-{1}", fileName, fileLength);
ClientSend(totalMsg, 2);
byte[] buffer = new byte[2 * 1024];
using (FileStream fs = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
{
int readLength = 0;
bool firstRead = true;
long sentFileLength = 0;
while ((readLength = fs.Read(buffer, 0, buffer.Length)) > 0 && sentFileLength < fileLength)
{
sentFileLength += readLength;
if (firstRead)
{
byte[] firstBuffer = new byte[readLength + 1];
firstBuffer[0] = 1;
Buffer.BlockCopy(buffer, 0, firstBuffer, 1, readLength);
socketClient.Send(firstBuffer, 0, readLength + 1, SocketFlags.None);
firstRead = false;
}
else
{
socketClient.Send(buffer, 0, readLength, SocketFlags.None);
}
}
fs.Close();
}
Message.AppendText("ZXY:" + GetTime() + "\r\n你发送了文件:" + fileName + "\r\n");
}
private void Send_Click(object sender, EventArgs e)
{
ClientSend(SendMsg.Text, 0);
}
private void SendMsg_keyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
ClientSend(SendMsg.Text, 0);
}
}
private void Sendfile_Click(object sender, EventArgs e)
{
SendFile(filePath);
}
public DateTime GetTime()
{
DateTime now = new DateTime();
now = DateTime.Now;
return now;
}
}
}
对于线程的IsBackground的理解,摘自于网络:
1、当在主线程中创建了一个线程,那么该线程的IsBackground默认是设置为FALSE的。
2、当主线程退出的时候,IsBackground=FALSE的线程还会继续执行下去,直到线程执行结束。
3、只有IsBackground=TRUE的线程才会随着主线程的退出而退出。
4、当初始化一个线程,把Thread.IsBackground=true的时候,指示该线程为后台线程。后台线程将会随着主线程的退出而退出。
5、原理:只要所有前台线程都终止后,CLR就会对每一个活在的后台线程调用Abort()来彻底终止应用程序。
C# 简单通信(实现文件传输)的更多相关文章
- 基于UDT connect连接通信以及文件传输--服务端
网上与UDT相关的资料不多,与UDT相关的源码例子更少.最近在接触UDT,也是因为缺少相关的资料,导致学习起来甚感痛苦.下面将我自己这两天弄出来的代码贴出来,希望对在寻找相关资料的童鞋有一定的帮助.与 ...
- 基于UDT connect连接通信以及文件传输--客户端
上面一篇文章中提出了服务端的,其实这里没有严格意义的服务端和客户端之分,因为我在代码中是基于UDP的,不存在服务端与客户端,两个都是对等的,只是我这里进行一下简单的区分而已.在这里,客户端所进行的主要 ...
- NAT穿透进行P2P文件传输
实现一个简单的p2p文件传输,主要解决NAT穿透问题,使用tcp协议传输. NAT背景介绍 简介 NAT(Network Address Translation ,网络地址转换) 是一种广泛应用的解决 ...
- QT从入门到入土(九)——TCP/IP网络通信(以及文件传输)
引言 TCP/IP通信(即SOCKET通信)是通过网线将服务器Server端和客户机Client端进行连接,在遵循ISO/OSI模型的四层层级构架的基础上通过TCP/IP协议建立的通讯.控制器可以设置 ...
- 【RL-TCPnet网络教程】第38章 TFTP简单文件传输基础知识
第38章 TFTP简单文件传输基础知识 本章节为大家讲解TFTP(Trivial File Transfer Protocol,简单文件传输协议)的基础知识,方便后面章节的实战操作. (本章 ...
- Python之路(第三十二篇) 网络编程:udp套接字、简单文件传输
一.UDP套接字 服务端 # udp是无链接的,先启动哪一端都不会报错 # udp没有链接,与tcp相比没有链接循环,只有通讯循环 server = socket.socket(socket.AF_I ...
- 网络编程 - socket通信/粘包/文件传输/udp - 总结
socket通信 1.简单的套接字通信 import socket phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.bin ...
- tftp简单文件传输协议搭建
TFTP 简单文件传输协议 安装 sudo apt-get install tftp tftpd openbsd-inetd 需要tftp tftpd openbsd-ine ...
- python 全栈开发,Day129(玩具开机提示语,为多个玩具发送点播,聊天界面,app录音,app与服务器端文件传输,简单的对话)
一.玩具开机提示语 先下载github代码,下面的操作,都是基于这个版本来的! https://github.com/987334176/Intelligent_toy/archive/v1.2.zi ...
随机推荐
- orcale的to_number方法
转自:https://blog.csdn.net/tiantangdizhibuxiang/article/details/81034893 TO_NUMBER函数()是Oracle中常用的类型转换函 ...
- SpringBoot2.x搭建SpringBootAdmin2.x
1 说明 全部配置基于1.8.0_111 当前SpringBoot使用2.0.5 SpringBootAdmin基于Eureka进行Client发现,Eureka搭建参见SpringBoot2.x搭建 ...
- ansible(三)
setup ansible_all_ipv4_addresses # ipv4的所有地址 ansible_all_ipv6_addresses # ipv6的所有地址 ansible_date_tim ...
- 浅析数据库(DB)、操作数据存储(ODS)和数据仓库(DW)的区别与联系
文章背景: 相信大部分刚接触上面三个概念的同学,都多多少少会有些迷惑,现在我就给大家简单分析下这三者的关系,希望大家对这三者的概念理解有所帮助吧. 本文主要从下面两类关系来叙述上面三者的关系: 数据库 ...
- Controller的激活(1)
Public interface IController { void Execute(RequestContext requestContext) } Public abstract Class C ...
- 2019牛客暑期多校训练营(第九场)A:Power of Fibonacci(斐波拉契幂次和)
题意:求Σfi^m%p. zoj上p是1e9+7,牛客是1e9: 对于这两个,分别有不同的做法. 前者利用公式,公式里面有sqrt(5),我们只需要二次剩余求即可. 后者mod=1e9,5才 ...
- python基础语法10 函数递归,模块,软件开发目录规范
函数递归: 函数递归指的是重复 “直接调用或间接调用” 函数本身, 这是一种函数嵌套调用的表现形式. 直接调用: 指的是在函数内置,直接调用函数本身. 间接调用: 两个函数之间相互调用间接造成递归. ...
- oracle中删除表:drop、delete、truncate
相同点,使用drop delete truncate 都会删除表中的内容 drop table 表名 delete from 表名(后面不跟where语句,则删除表中所有的数据) truncate t ...
- DSL的本质:领域构建的半成品
DSL的本质是使用通用和专用语言构建领域的半成品: 实际上是构建了一个世界观.小宇宙的半成品: 这个半成品包含领域的基本要素.联系方式和基本运行规律: 开发者使用这个半成品平台进行开发能达到事半功倍. ...
- 编程语言的类型修饰符modifiers
编程语言修饰符,代表语言要素与常规表达不同的语义: 这些语义的不同需要编译器和运行时作出不同的解释: 作用域.访问: 生命周期: 同步异步: 多态: 纯函数: 注解: 懒加载: 编译器合成: