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("服务器已经启动,开始监听..."+" "); -
} -
Socket socketConnect = null; -
private void WatchConnect() -
{ -
while (true) -
{ -
try -
{ -
socketConnect = socketWatch.Accept(); -
} -
catch (Exception ex) -
{ -
Message.AppendText(ex.Message); -
break; -
} -
Message.AppendText("客户端连接成功,可以开始通信..."+" "); -
//创建通信线程,感觉这个和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() + " " + recStr + " "); -
} -
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() + " 你成功接收了文件..." + fName + " 保存路径为:" + fPath + " "); -
} -
} -
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() + " " + SendStr+" "); -
} -
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() + " 您发送了文件:" + fileName + " "); -
} -
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("已经与服务端建立连接,可以开始通信... "); -
} -
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() + " " + recStr + " "); -
} -
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() + " 你成功接收了文件..." + fName + " 保存路径为:" + fPath + " "); -
} -
} -
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() + " " + SendStr + " "); -
} -
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() + " 你发送了文件:" + fileName + " "); -
} -
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()来彻底终止应用程序。