using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Net.Sockets; using System.Threading; using System.Net; using System.IO; namespace client { public partial class Client : Form { public Client() { InitializeComponent(); } //建立 1個客戶端套接字 和1個負責監聽服務端請求的線程 Socket socketClient = null; Thread threadClient = null; private delegate void SetText(string text); /// <summary> /// 連接服務端 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_login_Click(object sender, EventArgs e) { socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //這裏的ip地址,端口號都是服務端綁定的相關數據。 IPAddress ip = IPAddress.Parse(tb_ip.Text.Trim()); IPEndPoint endpoint = new IPEndPoint(ip, Convert.ToInt32(tb_socket.Text.Trim())); socketClient.Connect(endpoint);//連接有端口號與IP地址肯定服務端. ThreadStart thS = new ThreadStart(this.ReceMsg); //客戶端在接受服務端發送過來的數據是經過Socket 中的Receive方法, //該方法會阻斷線程,因此咱們本身爲該方法建立了一個線程 threadClient = new Thread(thS); threadClient.IsBackground = true;//設置後臺線程 threadClient.Start(); } //接收服務端數據 public void ReceMsg() { while (true)//持續監聽服務端發來的消息 { //定義一個2M的內存緩衝區 用於臨時性存儲接收到的信息 byte[] buffer = new byte[1024 * 1024 * 2]; //將客戶端套接字接收到的數據存入內存緩衝區, 並獲取其長度 int length = socketClient.Receive(buffer); //clientSocket.Receive(buffer);//接收服務端發送過來的數據 string ReceiveMsg = System.Text.Encoding.UTF8.GetString(buffer,0,length);//把接收到的字節數組轉成字符串顯示在文本框中,若是沒有長度,就會以零填充滿,後面的日期就會不顯示了。 ShowMsg("接收到數據: " + ReceiveMsg); } } //消息框裏面數據 void ShowMsg(string str) { if (this.tb_infor.InvokeRequired) { SetText st = new SetText(ShowMsg); this.Invoke(st, new object[] { str }); } else { //string Ystr = ""; //if (tb_infor.Text != "") //{ // Ystr = tb_infor.Text + "\r\n"; //} //tb_infor.Text = Ystr + str + GetCurrentTime(); //代替上面的方法 tb_infor.AppendText(str + GetCurrentTime() + "\r\n"); } } /// <summary> /// 打開文件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_openfile_Click(object sender, EventArgs e) { if (openFileDialog1.ShowDialog() == DialogResult.OK)//這裏須要小括號 ShowDialog() { tb_openfile.Text = openFileDialog1.FileName; } } #region /// <summary> /// 發送文件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_sendfile_Click(object sender, EventArgs e) { using (FileStream fs = new FileStream(tb_openfile.Text, FileMode.Open)) { byte[] buffer = new byte[1024 * 1024 * 2]; int readlength = fs.Read(buffer, 0, buffer.Length); byte[] filebuffer = new byte[readlength + 1]; filebuffer[0] = 1; Buffer.BlockCopy(buffer, 0, filebuffer, 1, readlength); //第一參數:表示源數組,第二個:表示從源數組中的哪一個位置開始拷貝,第三個:表示目標數組。,第四個:表示從目標數組的哪一個位置開始填充.,五:表示:拷貝多少數據 socketClient.Send(filebuffer); } } /// <summary> /// 發送消息 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_sendmessage_Click(object sender, EventArgs e) { string txtMsg = tb_message.Text; sendmessage(txtMsg); } /// <summary> /// 發送信息 /// </summary> /// <param name="txtMsg"></param> private void sendmessage(string txtMsg) { //將輸入的內容字符串轉換爲機器能夠識別的字節數組 byte[] buffer = Encoding.UTF8.GetBytes(txtMsg); byte[] messagebuffer = new byte[buffer.Length + 1];//定義一個新數組,加個標記位,標記是信息 messagebuffer[0] = 0;//設置標識,表示發送的是字符串 Buffer.BlockCopy(buffer, 0, messagebuffer, 1, buffer.Length);//源數組中的數據拷貝到新數組中 socketClient.Send(messagebuffer); ShowMsg("發送的數據: " + txtMsg); } #endregion /// <summary> /// 獲取當前系統時間的方法 /// </summary> /// <returns>當前時間</returns> private DateTime GetCurrentTime() { DateTime currentTime = new DateTime(); currentTime = DateTime.Now; return currentTime; } //快捷鍵 Enter發送信息 private void tb_message_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) {//當光標位於文本框時 若是用戶按下了鍵盤上的Enter鍵 if (e.KeyCode == Keys.Enter) { //則調用客戶端向服務端發送信息的方法 sendmessage(tb_message.Text.Trim()); } } } }
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Net.Sockets; using System.Net; using System.Threading; using System.IO; namespace socket { public partial class Server : Form { public Server() { InitializeComponent(); //關閉對文本框的非法線程操做檢查,不建議用 //TextBox.CheckForIllegalCrossThreadCalls = false; } Socket socketWatch = null;//負責監聽客戶端的套接字 Thread threadWatch = null;//負責監聽客戶端的線程 Thread threadMoveList = null;//負責去掉失敗的socket的ip //聲明一個帶參數委託處理文本顯示 private delegate void SetText(string text); //聲明一個處理ip添加到listbox的委託 private delegate void listboxAdd(string ipsocket); //聲明一個處理在listbox去除ip的委託 private delegate void listboxmove(string ipsocket); /// 開始服務端監聽 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_StartServer_Click(object sender, EventArgs e) { #region //建立一個Socket實例 //第一個參數表示使用ipv4 //第二個參數表示發送的是數據流 //第三個參數表示使用的協議是Tcp協議 socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //獲取ip地址 IPAddress ip = IPAddress.Parse(tb_ip.Text.Trim()); //建立一個網絡通訊節點,這個通訊節點包含了ip地址,跟端口號。 //這裏的端口咱們設置爲1029,這裏設置大於1024,爲何本身查一下端口號範圍使用說明。 IPEndPoint endPoint = new IPEndPoint(ip, int.Parse(tb_socket.Text.Trim())); //設置SOCKET容許多個SOCKET訪問同一個本地IP地址和端口號 socketWatch.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); //Socket綁定網路通訊節點 socketWatch.Bind(endPoint); //將套接字的監聽隊列長度限制爲10 socketWatch.Listen(10); ShowMsg("開啓監聽!"); //實力化一個線程上的委託 ThreadStart threadDelegate = new ThreadStart(this.accpet);//還須要invoke //實力化一個處理線程委託的的新線程 threadWatch = new Thread(threadDelegate); //等同於上面兩句newthread = new Thread(new ThreadStart(this.accpet)); threadWatch.IsBackground = true; threadWatch.Start(); #endregion } //消息框裏面數據 public void ShowMsg(string str) { if (this.tb_infor.InvokeRequired) { //實例化一個委託 SetText d = new SetText(ShowMsg); this.Invoke(d, new object[] { str }); } else { //string Ystr = ""; //if (tb_infor.Text != "") //{ // Ystr = tb_infor.Text + "\r\n"; //} //this.tb_infor.Text = Ystr + str + GetCurrentTime(); tb_infor.AppendText(str + GetCurrentTime() + "\r\n"); } } Dictionary<string, Socket> socketDir = new Dictionary<string, Socket>();//將每個與客戶端進行通訊的Socket放到該集合中. public void accpet() { while (true)//注意該循環,服務端要持續監聽,要否則一個客戶端連接事後就沒法連接第二個客戶端了。 { Socket SocketConnection = null;//建立一個負責和客戶端通訊的套接字 //建立一個接收客戶端通訊的Socket SocketConnection = socketWatch.Accept(); socketDir.Add(SocketConnection.RemoteEndPoint.ToString(), SocketConnection);//將負責與客戶端進行通訊的Socket實例添加到集合中。 //若是監聽到客戶端有連接,則運行到下一部,提示,連接成功! listboxADD(SocketConnection.RemoteEndPoint.ToString()); ShowMsg("連接成功!"); //建立一個通訊線程 ParameterizedThreadStart pts = new ParameterizedThreadStart(ServerRecMsg); Thread thr = new Thread(pts); //在定義窗體線程的時候,設置線程啓動前狀態就好了,解決異常 thr.SetApartmentState(ApartmentState.STA); thr.IsBackground = true; //啓動線程 thr.Start(SocketConnection); } } /// <summary> /// 在ip欄裏添加創建socket的ip /// </summary> private void listboxADD(string ipsocket) { if (this.ltb_IP.InvokeRequired) { listboxAdd list = new listboxAdd(listboxADD); this.Invoke(list,new object[]{ipsocket}); } else { ltb_IP.Items.Add(ipsocket); } } } /// <summary> /// 向客戶端發送信息 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btn_sendany_Click(object sender, EventArgs e) { string SendMsg = tb_message.Text; if (SendMsg != "") { byte[] buffer = System.Text.Encoding.UTF8.GetBytes(SendMsg); //將要發送的數據,生成字節數組。 if (!string.IsNullOrEmpty(this.ltb_IP.Text)) { string ipendpoint = this.ltb_IP.SelectedItem .ToString();//在服務端,選擇與客戶端進行通訊的IP地址與端口號 socketDir[ipendpoint].Send(buffer);//向客戶端發送數據 ShowMsg("向客戶端發送了:" + SendMsg); } else { MessageBox.Show("請選擇與哪一個客戶端進行通訊"); } } } /// <summary> /// 獲取當前系統時間的方法 /// </summary> /// <returns>當前時間</returns> private DateTime GetCurrentTime() { DateTime currentTime = new DateTime(); currentTime = DateTime.Now; return currentTime; } /// <summary> /// 接收客戶端發來的信息 /// </summary> /// <param name="socketClientPara">客戶端套接字對象</param> private void ServerRecMsg(object socketClientPara) { Socket socketServer = socketClientPara as Socket; while (true) { int length = -1; //建立一個內存緩衝區 其大小爲1024*1024字節 即1M byte[] arrServerRecMsg = new byte[1024 * 1024 * 2]; try //因爲Socket中的Receive方法容易拋出異常,因此咱們在這裏要捕獲異常。 { //將接收到的信息存入到內存緩衝區,並返回其字節數組的長度 length = socketServer.Receive(arrServerRecMsg); } catch (SocketException ex)//注意:在捕獲異常時,先肯定具體的異常類型。 { ShowMsg("出現了異常:" + ex.Message); socketDir.Remove(socketServer.RemoteEndPoint.ToString());//若是出現了異常,將該Socket實例從集合中移除 //ParameterizedThreadStart Delegatemove = new ParameterizedThreadStart(listboxmoveway);//用ParameterizedThreadStart其方法能夠帶一個object類型的參數 //threadMoveList = new Thread(Delegatemove); //threadMoveList.IsBackground = true; //threadMoveList.Start(); //listboxmoveway(socketServer.RemoteEndPoint);//調用方法 //socketServer.Close(); break;//出現異常之後,終止整個循環的執行 } catch (Exception ex) { ShowMsg("出現了異常:" + ex.Message); break; } if (arrServerRecMsg[0] == 0)//表示字符串 { //將機器接受到的字節數組轉換爲人能夠讀懂的字符串 string strSRecMsg = Encoding.UTF8.GetString(arrServerRecMsg, 1, length-1); //將發送的字符串信息附加到文本框txtMsg上 ShowMsg("接受客戶端數據:" + strSRecMsg); } else if (arrServerRecMsg[0] == 1) { SaveFileDialog savefile=new SaveFileDialog(); if(savefile.ShowDialog()==DialogResult.OK) { using(FileStream fs=new FileStream(savefile.FileName,FileMode.Create)) { fs.Write(arrServerRecMsg, 1, length - 1);//將文件寫到磁盤上,從1開始到receiveLength-1 ShowMsg("文件寫成功!" ); } } } } } } }