TCP傳送數據可以分為同步傳送和異步傳送,首先這裡使用了TCP的同步傳送方式,學習了TCP同步傳送數據的原理。
同步工作方式是指利用TCP編寫的程序執行到監聽或者接受數據語句的時候,在未完成當前工作(偵聽到連接請求或接收到對方發送來的數據)前不在繼續往下執行,線程處於阻塞狀態,直到該語句完成響應的工作以後才繼續執行下一語句。
TCP協議只需要將數據以字節流的形式發送到緩存,在他自己看來就好像已經完成了此動作,然而此時的數據讓可能還在緩沖區。至於對方是否真正的接收到數據,就不再負責了。這以後可以繼續執行其他的操作,可以繼續發送數據,不會阻塞,而真正的發送是由IP協議完成的。IP層為TCP協議提供了實際的傳輸服務,從而對上層屏蔽了主動操作時同步和異步的差異。
在同步方式中,比如服務器端有一條語句是接收客戶端數據的工作,但是客戶端一直沒有發送數據,則一直處於等待狀態。一下的例子就給出了這種實現功能。
但是,對於請求和發送語句,同步方式和異步方式沒有差異,因為程序執行發送語句的時候是直接將數據發送出去而不管對方是否准備好,當客戶端發起連接請求時,如果服務器沒有打開,則會返回失敗信息。此時,數據有可能仍然在本地緩沖區還沒有發送出去,這樣,TCP協議為我們隱藏了這一細節。
異步工作方式中,監聽程序或者接受語句,不論當前工作是否完成,都會繼續往下執行。
這裡寫的服務器和客戶端的程序截圖:
程序解釋:1. 首先客戶端連接到服務器。顯示連接成功。
2. 給服務器發送了一個"test from client",然後在服務器端點擊接收,可以收到客戶端發來的數據。
3. 服務器端發送"test from server",因為在程序中寫的是連續發送三次,所以這裡服務器端發送了三次數據,在客戶端點擊三次接收,就可以收到三條服務器發來的信息。如果只是點擊一次,只能收到服務器發來的一條信息。
4.然後又從客戶端給服務器發送了兩條消息,服務器接收兩次也成功。
5. 如果你在客戶端沒有給服務器發送消息的時候點擊接收消息,這個時候服務器的接收消息線程會阻塞在等待狀態,直到客戶端發送數據過去,服務器那裡就可以顯示接收到的數據了。這裡就是同步方式的特點了,接收消息的語句會處於阻塞狀態。
在本程序中,出錯的情況是:在客戶端沒有傳送數據的前提下,連續多次點擊服務器的接收消息操作,因為程序中寫的是每次接收開啟一個線程,這樣多次點擊接收就會有多個線程同時讀網絡數據緩沖區,肯定會造成莫名其妙的錯誤。
程序下載地址:http://www.BkJia.com/uploadfile/2012/0607/20120607105137520.rar
重點語句說明:
tcpClient = tcpListener.AcceptTcpClient();
這裡的接收客戶端連接請求時同步方式,如果沒有客戶端請求,則一直處於阻塞狀態,所以一定要放在單獨的線程中。
try
{
string message = br.ReadString();
ShowMsg(message);
}
這裡的接收消息,也是同步操作,如果沒有消息到來,則一直處於阻塞狀態,所以也要放在單獨的線程中。
[csharp] networkStream = tcpClient.GetStream();
// 通過BinaryWriter,BinaryReader操作網絡流,測試是否可以方便的操作網絡流
br = new BinaryReader(networkStream);
bw = new BinaryWriter(networkStream);
networkStream = tcpClient.GetStream();
// 通過BinaryWriter,BinaryReader操作網絡流,測試是否可以方便的操作網絡流
br = new BinaryReader(networkStream);
bw = new BinaryWriter(networkStream);
這幾行代碼把從網絡連接獲取的NetworkStream的操作封裝到BinaryWriter,BinaryReader兩個類中,通過這兩個類可以方便操作網絡流的發送和接收,都不用再認為的接收和發送消息,只需要用BinaryWriter,BinaryReader寫消息和讀消息就可以了,使用起來很方便,我也是第一次用。
本項目的主要代碼.
服務器:
[csharp] 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.IO;
using System.Net;
using System.Threading;
namespace TCPServer
{
public partial class Form1 : Form
{
delegate void ShowInfo(string s);
IPAddress serverIP;
int port = 1234;
TcpListener tcpListener;
TcpClient tcpClient;
private NetworkStream networkStream;
BinaryWriter bw;
BinaryReader br;
int sendCount = 1;
int receiveCount = 1;
public Form1()
{
serverIP = IPAddress.Parse("10.108.13.27");
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
tcpListener = new TcpListener(serverIP, port);
tcpListener.Start();
ShowMsg("開始監聽");
Thread listenThread = new Thread(new ThreadStart(acceptClientConn));
listenThread.IsBackground = true;
listenThread.Start();
}
private void acceptClientConn()
{
try
{
tcpClient = tcpListener.AcceptTcpClient();
if (tcpClient != null)
{
ShowMsg("接受一個連接請求!");
networkStream = tcpClient.GetStream();
// 通過BinaryWriter,BinaryReader操作NetworkStream
bw = new BinaryWriter(networkStream);
br = new BinaryReader(networkStream);
}
}
catch (System.Exception ex)
{
//
}
}
/// <summary>
/// 線程安全的現實信息
/// </summary>
/// <param name="info"></param>
public void ShowMsg(string info)
{
ShowInfo call = delegate(string s) { this.richTextBox1.Text += s + "\n"; };
this.richTextBox1.Invoke(call, info);
}
private void button2_Click(object sender, EventArgs e)
{
tcpListener.Stop();
}
private void button5_Click(object sender, EventArgs e)
{
if (br!=null)
{
br.Close();
}
if (bw!=null)
{
bw.Close();
}
if (tcpClient!=null)
{
tcpClient.Close();
}
}
private void button4_Click(object sender, EventArgs e)
{
Thread receiveThread = new Thread(new ThreadStart(receiveMeg));
receiveThread.IsBackground = true;
receiveThread.Start();
}
private void receiveMeg()
{
for (int i = 0; i < receiveCount;i++ )
{
try
{
string message = br.ReadString();
ShowMsg(message);
}
catch (System.Exception ex)
{
if (br != null)
{
br.Close();
}
if (bw != null)
{
bw.Close();
}
if (tcpClient != null)
{
tcpClient.Close();
}
DateTime now = DateTime.Now;
while (now.AddSeconds(3) > DateTime.Now) { }
// 重啟線程接受連接請求
Thread threadAccept = new Thread(new ThreadStart(acceptClientConn));
threadAccept.IsBackground = true;
threadAccept.Start();
}
}
}
private void button3_Click(object sender, EventArgs e)
{
Thread sendThread = new Thread(new ParameterizedThreadStart(sendMessage));
sendThread.IsBackground = true;
string s = this.textBox1.Text;
sendThread.Start(s);
}
private void sendMessage(object msg)
{
for (int i = 0; i < sendCount;i++ )
{
try
{
bw.Write(msg.ToString());
DateTime now = DateTime.Now;
while (now.AddSeconds(1)>DateTime.Now)
{
//
}
bw.Flush();
ShowMsg("發送成功!");
}
catch (System.Exception ex)
{
if (br != null)
{
br.Close();
}
if (bw != null)
{
bw.Close();
}
if (tcpClient != null)
{
tcpClient.Close();
}
DateTime now = DateTime.Now;
while (now.AddSeconds(3) > DateTime.Now) { }
// 重啟線程接受連接請求
Thread threadAccept = new Thread(new ThreadStart(acceptClientConn));
threadAccept.IsBackground = true;
threadAccept.Start();
}
}
}
}
}
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.IO;
using System.Net;
using System.Threading;
namespace TCPServer
{
public partial class Form1 : Form
{
delegate void ShowInfo(string s);
IPAddress serverIP;
int port = 1234;
TcpListener tcpListener;
TcpClient tcpClient;
private NetworkStream networkStream;
BinaryWriter bw;
BinaryReader br;
int sendCount = 1;
int receiveCount = 1;
public Form1()
{
serverIP = IPAddress.Parse("10.108.13.27");
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
tcpListener = new TcpListener(serverIP, port);
tcpListener.Start();
ShowMsg("開始監聽");
Thread listenThread = new Thread(new ThreadStart(acceptClientConn));
listenThread.IsBackground = true;
listenThread.Start();
}
private void acceptClientConn()
{
try
{
tcpClient = tcpListener.AcceptTcpClient();
if (tcpClient != null)
{
ShowMsg("接受一個連接請求!");
networkStream = tcpClient.GetStream();
// 通過BinaryWriter,BinaryReader操作NetworkStream
bw = new BinaryWriter(networkStream);
br = new BinaryReader(networkStream);
}
}
catch (System.Exception ex)
{
//
}
}
/// <summary>
/// 線程安全的現實信息
/// </summary>
/// <param name="info"></param>
public void ShowMsg(string info)
{
ShowInfo call = delegate(string s) { this.richTextBox1.Text += s + "\n"; };
this.richTextBox1.Invoke(call, info);
}
private void button2_Click(object sender, EventArgs e)
{
tcpListener.Stop();
}
private void button5_Click(object sender, EventArgs e)
{
if (br!=null)
{
br.Close();
}
if (bw!=null)
{
bw.Close();
}
if (tcpClient!=null)
{
tcpClient.Close();
}
}
private void button4_Click(object sender, EventArgs e)
{
Thread receiveThread = new Thread(new ThreadStart(receiveMeg));
receiveThread.IsBackground = true;
receiveThread.Start();
}
private void receiveMeg()
{
for (int i = 0; i < receiveCount;i++ )
{
try
{
string message = br.ReadString();
ShowMsg(message);
}
catch (System.Exception ex)
{
if (br != null)
{
br.Close();
}
if (bw != null)
{
bw.Close();
}
if (tcpClient != null)
{
tcpClient.Close();
}
DateTime now = DateTime.Now;
while (now.AddSeconds(3) > DateTime.Now) { }
// 重啟線程接受連接請求
Thread threadAccept = new Thread(new ThreadStart(acceptClientConn));
threadAccept.IsBackground = true;
threadAccept.Start();
}
}
}
private void button3_Click(object sender, EventArgs e)
{
Thread sendThread = new Thread(new ParameterizedThreadStart(sendMessage));
sendThread.IsBackground = true;
string s = this.textBox1.Text;
sendThread.Start(s);
}
private void sendMessage(object msg)
{
for (int i = 0; i < sendCount;i++ )
{
try
{
bw.Write(msg.ToString());
DateTime now = DateTime.Now;
while (now.AddSeconds(1)>DateTime.Now)
{
//
}
bw.Flush();
ShowMsg("發送成功!");
}
catch (System.Exception ex)
{
if (br != null)
{
br.Close();
}
if (bw != null)
{
bw.Close();
}
if (tcpClient != null)
{
tcpClient.Close();
}
DateTime now = DateTime.Now;
while (now.AddSeconds(3) > DateTime.Now) { }
// 重啟線程接受連接請求
Thread threadAccept = new Thread(new ThreadStart(acceptClientConn));
threadAccept.IsBackground = true;
threadAccept.Start();
}
}
}
}
}
客戶端:
[csharp] 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;
using System.Net.Sockets;
using System.IO;
using System.Threading;
namespace TCPClient
{
public partial class Form1 : Form
{
delegate void ShowMeg(string s);
IPAddress serverIP;
int port = 1234;
NetworkStream networkStream;
BinaryWriter bw;
BinaryReader br;
TcpClient tcpClient;
int sendCount = 1;
int receiveCount = 1;
public Form1()
{
serverIP = IPAddress.Parse("10.108.13.27");
InitializeComponent();
}
private void bt_connect_Click(object sender, EventArgs e)
{
// 通過一個新的線程連接
Thread connectThread = new Thread(new ThreadStart(ConnectServer));
connectThread.IsBackground = true;
connectThread.Start();
}
/// <summary>
/// 連接服務器
/// </summary>
private void ConnectServer()
{
try
{
tcpClient = new TcpClient();
tcpClient.Connect(serverIP, port);
DateTime now = DateTime.Now;
while (now.AddSeconds(1) > DateTime.Now) { }
if (tcpClient!=null)
{
// 連接成功
ShowInfo("連接成功!");
networkStream = tcpClient.GetStream();
// 通過BinaryWriter,BinaryReader操作網絡流,測試是否可以方便的操作網絡流
br = new BinaryReader(networkStream);
bw = new BinaryWriter(networkStream);
}
}
catch
{
// 連接失敗
ShowInfo("連接失敗!");
}
}
private void ShowInfo(string info)
{
ShowMeg call = delegate(string s) { this.richTextBox1.Text += s + "\n"; };
this.richTextBox1.Invoke(call,info);
}
/// <summary>
/// 斷開連接
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
if (br!=null)
{
br.Close();
}
if (bw!=null)
{
bw.Close();
}
if (tcpClient!=null)
{
tcpClient.Close();
}
ShowInfo("成功斷開連接!");
}
private void button2_Click(object sender, EventArgs e)
{
// 在新的線程中發送數據
Thread sendThread = new Thread(new ParameterizedThreadStart(SendMessage));
sendThread.IsBackground = true;
string message = this.textBox1.Text;
sendThread.Start(message);
}
private void SendMessage(object message)
{
int sendTimeDelay = 1;
for (int i = 0; i < sendCount;i++ )
{
try
{
bw.Write(message.ToString());
DateTime now = DateTime.Now;
while (now.AddSeconds(sendTimeDelay) > DateTime.Now) { }
bw.Flush();
ShowInfo("發送成功");
}
catch (System.Exception ex)
{
ShowInfo("發送失敗");
if (br != null)
{
br.Close();
}
if (bw != null)
{
bw.Close();
}
if (tcpClient != null)
{
tcpClient.Close();
}
//ShowInfo("成功斷開連接!");
}
}
}
private void button3_Click(object sender, EventArgs e)
{
//在新的線程中接收
Thread receiveThread = new Thread(new ThreadStart(ReceiveMeg));
receiveThread.IsBackground = true;
receiveThread.Start();
}
private void ReceiveMeg()
{
for (int i = 0; i < receiveCount; i++)
{
try
{
string message = br.ReadString();
if (message!=null)
{
ShowInfo(message);
}
}
catch (System.Exception ex)
{
ShowInfo("接收失敗!");
}
}
}
}
}
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;
using System.Net.Sockets;
using System.IO;
using System.Threading;
namespace TCPClient
{
public partial class Form1 : Form
{
delegate void ShowMeg(string s);
IPAddress serverIP;
int port = 1234;
NetworkStream networkStream;
BinaryWriter bw;
BinaryReader br;
TcpClient tcpClient;
int sendCount = 1;
int receiveCount = 1;
public Form1()
{
serverIP = IPAddress.Parse("10.108.13.27");
InitializeComponent();
}
private void bt_connect_Click(object sender, EventArgs e)
{
// 通過一個新的線程連接
Thread connectThread = new Thread(new ThreadStart(ConnectServer));
connectThread.IsBackground = true;
connectThread.Start();
}
/// <summary>
/// 連接服務器
/// </summary>
private void ConnectServer()
{
try
{
tcpClient = new TcpClient();
tcpClient.Connect(serverIP, port);
DateTime now = DateTime.Now;
while (now.AddSeconds(1) > DateTime.Now) { }
if (tcpClient!=null)
{
// 連接成功
ShowInfo("連接成功!");
networkStream = tcpClient.GetStream();
// 通過BinaryWriter,BinaryReader操作網絡流,測試是否可以方便的操作網絡流
br = new BinaryReader(networkStream);
bw = new BinaryWriter(networkStream);
}
}
catch
{
// 連接失敗
ShowInfo("連接失敗!");
}
}
private void ShowInfo(string info)
{
ShowMeg call = delegate(string s) { this.richTextBox1.Text += s + "\n"; };
this.richTextBox1.Invoke(call,info);
}
/// <summary>
/// 斷開連接
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
if (br!=null)
{
br.Close();
}
if (bw!=null)
{
bw.Close();
}
if (tcpClient!=null)
{
tcpClient.Close();
}
ShowInfo("成功斷開連接!");
}
private void button2_Click(object sender, EventArgs e)
{
// 在新的線程中發送數據
Thread sendThread = new Thread(new ParameterizedThreadStart(SendMessage));
sendThread.IsBackground = true;
string message = this.textBox1.Text;
sendThread.Start(message);
}
private void SendMessage(object message)
{
int sendTimeDelay = 1;
for (int i = 0; i < sendCount;i++ )
{
try
{
bw.Write(message.ToString());
DateTime now = DateTime.Now;
while (now.AddSeconds(sendTimeDelay) > DateTime.Now) { }
bw.Flush();
ShowInfo("發送成功");
}
catch (System.Exception ex)
{
ShowInfo("發送失敗");
if (br != null)
{
br.Close();
}
if (bw != null)
{
bw.Close();
}
if (tcpClient != null)
{
tcpClient.Close();
}
//ShowInfo("成功斷開連接!");
}
}
}
private void button3_Click(object sender, EventArgs e)
{
//在新的線程中接收
Thread receiveThread = new Thread(new ThreadStart(ReceiveMeg));
receiveThread.IsBackground = true;
receiveThread.Start();
}
private void ReceiveMeg()
{
for (int i = 0; i < receiveCount; i++)
{
try
{
string message = br.ReadString();
if (message!=null)
{
ShowInfo(message);
}
}
catch (System.Exception ex)
{
ShowInfo("接收失敗!");
}
}
}
}
}
摘自 Watkins.Song