https://blog.csdn.net/Sayesan/article/details/82185772數組
以前寫過一個簡單通訊傳輸,不過只有聊天的功能,如今實現了文件傳輸的功能,借鑑於網上一篇博客,不過他寫的僅僅是客戶端對於服務器發送文件,我稍微優化了這個功能,實現了,端與端之間信息的互發和文件的互發,感受學習這些新的東西,還剛開始,進度很慢,不少東西都須要重新去學習,不過慢慢來!Fighting!!!服務器
服務器:網絡
using System;
socket
using System.Collections.Generic;
學習
using System.ComponentModel;
優化
using System.Data;
this
using System.Drawing;
spa
using System.Linq;
.net
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的理解,摘自於網絡:
一、當在主線程中建立了一個線程,那麼該線程的IsBackground默認是設置爲FALSE的。二、當主線程退出的時候,IsBackground=FALSE的線程還會繼續執行下去,直到線程執行結束。三、只有IsBackground=TRUE的線程纔會隨着主線程的退出而退出。四、當初始化一個線程,把Thread.IsBackground=true的時候,指示該線程爲後臺線程。後臺線程將會隨着主線程的退出而退出。五、原理:只要全部前臺線程都終止後,CLR就會對每個活在的後臺線程調用Abort()來完全終止應用程序。