久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

基于TCP異步的聊天室程序 - 钚再想她 - 博客園

 coding 2010-08-01

話說這個學(xué)期我們有一門課叫“中間件”,老師叫我們做一個基于TCP的聊天程序,,主要結(jié)構(gòu)如圖

1.所有Client端需要與Server端連接(感覺這句話好白癡,,TCP肯定要連接了才能工作)

2.Client端的功能是可以群發(fā)和私聊(用過QQ都應(yīng)該知道什么是群發(fā)和私聊吧),但都必須經(jīng)過Server端中轉(zhuǎn),,也就是實現(xiàn)了類似通訊中間件的功能,。

 

PS:開始寫之前我是對網(wǎng)絡(luò)編程這塊完全沒有認(rèn)識的,上網(wǎng)找了幾個TCP的程序,,都是只能實現(xiàn)群發(fā)功能,,或者只能實現(xiàn)client與server之間相互發(fā)的功能,

還沒有哪個是可以實現(xiàn)上面所說的功能的程序的(如果有的請留言給我,,我去下一個下來學(xué)習(xí)一下,,O(∩_∩)O謝謝)。

 

實現(xiàn)方法有好多,,用Socket類可以實現(xiàn),,用 TcpClient類和TcpListener類也可以實現(xiàn),我就選擇了后者,,因為比較簡單,。

下面就列一下我用到的技術(shù):

多線程,異步回調(diào),,委托,,設(shè)計模式的觀察者模式…………

 

先讓大家看一下客戶端和服務(wù)器端的界面先吧(本人不會做界面,而且界面上有很多Label是用來檢查接收的情況,,請大家選擇性過濾掉)

server端的

client端的

1.Server端先啟動服務(wù),新建一個線程,,綁定一個套接字,之后監(jiān)聽

2.Client端點擊連接之后,就會與Server端建立連接,。

3.每當(dāng)有一個Client加入Server時,,Server都會通知所有的Client更新用戶列表(觀察者模式)

4.點私聊和用戶之后,就可以私聊;點群發(fā),,就發(fā)個所有用戶,。

 

代碼解說,先看看解決方案

 

先說一下client端

 

聲明變量
System.Collections.ArrayList clientlist = new System.Collections.ArrayList();
private bool isExit = false;
private delegate void SetListBoxCallBack(string str);
private SetListBoxCallBack setlistboxcallback;
private delegate void SetTextBoxReceiveCallBack(string str);
private SetTextBoxReceiveCallBack settextboxreceivecallback;
private delegate void SetComboBoxCallBack(string str);
private SetComboBoxCallBack setcomboboxcallback;
private delegate void RemoveComboBoxItemsCallBack(DataReadWrite datareadwrite);
private RemoveComboBoxItemsCallBack removecomboboxcallback;
private TcpClient client;
private NetworkStream ns;
private ManualResetEvent allDone = new ManualResetEvent(false);
構(gòu)造函數(shù)
public ClientMain()
{
InitializeComponent();
setlistboxcallback
= new SetListBoxCallBack(SetListBox); //注冊listbox回調(diào)函數(shù)
settextboxreceivecallback = new SetTextBoxReceiveCallBack(SetTextBoxReceive); ////注冊textbox回調(diào)函數(shù)
setcomboboxcallback = new SetComboBoxCallBack(SetComboBox); ////注冊combobox回調(diào)函數(shù)
removecomboboxcallback = new RemoveComboBoxItemsCallBack(RemoveComboBoxItems);
}
//注冊combobox刪除的回調(diào)函數(shù)
連接按鈕
//連接按鈕事件
private void btn_Connect_Click(object sender, EventArgs e)
{
client
= new TcpClient(AddressFamily.InterNetwork);
IPAddress serverip
= IPAddress.Parse(txt_Server.Text);
//采用的是異步方式
AsyncCallback receiveCallBack = new AsyncCallback(ReceiveCallBack);
allDone.Reset();

try
{
//開始連接
client.BeginConnect(serverip, Convert.ToInt32(txt_Port.Text),receiveCallBack,client);
txt_ReceiveMsg.Invoke(settextboxreceivecallback,
string.Format("本機終結(jié)點:{0}", client.Client.LocalEndPoint));
txt_ReceiveMsg.Invoke(settextboxreceivecallback,
"開始與服務(wù)器連接");
allDone.WaitOne();
btn_Connect.Enabled
= false;
}
catch
{
MessageBox.Show(
"登錄服務(wù)器失敗,,請確認(rèn)服務(wù)器是否正常工作,!");
}
}
接收和回調(diào)
//接收回調(diào)函數(shù)
private void ReceiveCallBack(IAsyncResult iar)
{
allDone.Set();
try
{
client
= (TcpClient)iar.AsyncState;
client.EndConnect(iar);
txt_ReceiveMsg.Invoke(settextboxreceivecallback,
string.Format("與服務(wù)器{0}連接成功", client.Client.RemoteEndPoint));
ns
= client.GetStream();
DataRead dataRead
= new DataRead(ns, client.ReceiveBufferSize);
ns.BeginRead(dataRead.msg,
0, dataRead.msg.Length, ReadCallBack, dataRead);
}
catch
{
MessageBox.Show(
"已經(jīng)與服務(wù)器斷開連接!");
this.Close();
}

}

//讀取回調(diào)函數(shù)
private void ReadCallBack(IAsyncResult iar)
{
try
{
DataRead dataread
= (DataRead)iar.AsyncState;
int recv = dataread.ns.EndRead(iar);
lbluserlist.Text
= Encoding.Unicode.GetString(dataread.msg, 0, recv);
string userlist1 = lbluserlist.Text;
if (userlist1.StartsWith("#"))
{
lb_Users.Items.Clear();
string[] abc = userlist1.Split(new char[] { '#' });
for (int i = 1; i < abc.Length ; i++)
lb_Users.Items.Add(abc[i]);
}
else
txt_ReceiveMsg.Invoke(settextboxreceivecallback, Encoding.Unicode.GetString(dataread.msg,
0, recv));

if (isExit == false)
{

dataread
= new DataRead(ns, client.ReceiveBufferSize);
ns.BeginRead(dataread.msg,
0, dataread.msg.Length, ReadCallBack, dataread);
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
finally
{ }
}
發(fā)送功能
//發(fā)送按鈕事件
private void btn_Send_Click(object sender, EventArgs e)
{
//如果群發(fā)按鈕被選中時
if (rbteam.Checked == true)
{
//lb_Users.SelectedItems.Clear();
SendString(txt_SendMsg.Text);
}
//如果私聊按鈕被選中時
else if (rbself.Checked == true)
{
if (lb_Users.SelectedItem != null)
SendString(
"#" + lb_Users.SelectedItem.ToString().Trim() + "#" + txt_SendMsg.Text);
//label10.Text = "#" + lb_Users.SelectedItem.ToString().Trim() + "#" + txt_SendMsg.Text;
else
MessageBox.Show(
"你還沒有選取要私聊的對象");
}

//label9.Text = "對大家說:" + txt_SendMsg.Text;

txt_SendMsg.Clear();
}


//發(fā)送函數(shù)
private void SendString(string str)
{
try
{
byte[] bytesdata = Encoding.Unicode.GetBytes(str + "\r\n");
ns.BeginWrite(bytesdata,
0, bytesdata.Length, new AsyncCallback(SendCallBack), ns);
ns.Flush();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
finally
{ }
}

//發(fā)送回調(diào)函數(shù)
private void SendCallBack(IAsyncResult iar)
{
try
{
ns.EndWrite(iar);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
finally
{ }
}
回調(diào)函數(shù)的實現(xiàn)
//listbox回調(diào)函數(shù)
private void SetListBox(string str)
{
lb_Users.Items.Add(str);
}

//txtbox回調(diào)函數(shù)
private void SetTextBoxReceive(string str)
{
txt_ReceiveMsg.AppendText(str
+"\r\n");
}

 

 

在看看Server端

 

開始階段
public ServerMain()
{
InitializeComponent();
setlistboxcallback
= new SetListBoxCallBack(SetLbListBox);
setlistboxcallback2
= new SetListBoxCallBack(SetListBox);
removelistboxcallback
= new RemoveListBoxCallBack(RemoveListBoxItems);
setcomboboxcallback
= new SetComboBoxCallBack(SetComboBox);
removecomboboxcallback
= new RemoveComboBoxItemsCallBack(RemoveComboBoxItems);
}



private bool isExit = false;
System.Collections.ArrayList clientlist
= new System.Collections.ArrayList();
TcpListener listener;
private delegate void SetListBoxCallBack(string str);
private SetListBoxCallBack setlistboxcallback;
private SetListBoxCallBack setlistboxcallback2;
private delegate void RemoveListBoxCallBack(DataReadWrite datareadwrite);
private RemoveListBoxCallBack removelistboxcallback;
private ManualResetEvent allDone = new ManualResetEvent(false);
private delegate void SetComboBoxCallBack(string str);
private SetComboBoxCallBack setcomboboxcallback;
private delegate void RemoveComboBoxItemsCallBack(DataReadWrite datareadwrite);
private RemoveComboBoxItemsCallBack removecomboboxcallback;

//開始服務(wù)按鈕
private void btn_Start_Click(object sender, EventArgs e)
{
//新建線程接受connect
Thread myThread = new Thread(new ThreadStart(AcceptConnection));
myThread.Start();
btn_Start.Enabled
= false;
btn_End.Enabled
=true;
}

//線程AcceptConnection
private void AcceptConnection()
{
IPAddress[] ip
= Dns.GetHostAddresses(Dns.GetHostName());
//IPAddress ipp = IPAddress.Parse("192.168.76.103");
listener = new TcpListener(ip[0], Convert.ToInt32(txt_ServerPort.Text));
listener.Start();
while (isExit == false)
{
try
{
allDone.Reset();
AsyncCallback callback
= new AsyncCallback(AcceptTcpClientCallBack);
lst_ServerList.Invoke(setlistboxcallback,
"開始等待連接");
listener.BeginAcceptTcpClient(callback, listener);
allDone.WaitOne();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
break;
}
finally
{ }
}
}

private void AcceptTcpClientCallBack(IAsyncResult iar)
{
try
{
allDone.Set();
TcpListener mylistener
= (TcpListener)iar.AsyncState;
TcpClient client
= mylistener.EndAcceptTcpClient(iar);
lst_ServerList.Invoke(setlistboxcallback,
"已接收客戶連接" + client.Client.RemoteEndPoint);
listBox1.Invoke(setlistboxcallback2, client.Client.RemoteEndPoint.ToString());
comboBox1.Invoke(setcomboboxcallback, client.Client.RemoteEndPoint.ToString());
DataReadWrite datareadwrite
= new DataReadWrite(client);
clientlist.Add(datareadwrite);

//發(fā)送成員列表,,這里用了觀察者模式
SendList();

//與服務(wù)器連接后的不同的客戶端的datareadwrite開始異步接收數(shù)據(jù)
datareadwrite.ns.BeginRead(datareadwrite.read, 0, datareadwrite.read.Length, ReadCallBack, datareadwrite);
}
catch (Exception e)
{
lst_ServerList.Invoke(setlistboxcallback, e.Message);
//MessageBox.Show(e.Message);
return;
}
finally
{ }
}

private void SendList()
{
string userlist = "";
for (int i = 0; i < clientlist.Count; i++)
{
userlist
= userlist + "#" + ((DataReadWrite)clientlist[i]).client.Client.RemoteEndPoint.ToString();
label14.Text
= userlist;
}
foreach (DataReadWrite drw in clientlist)
SendString(drw, userlist);
}
運行階段
//讀取消息回調(diào)函數(shù)
private void ReadCallBack(IAsyncResult iar)
{
DataReadWrite datareadwrite
= (DataReadWrite)iar.AsyncState;
try
{

int recv = datareadwrite.ns.EndRead(iar);
string aa = Encoding.Unicode.GetString(datareadwrite.read, 0, recv);
//string bb = "";
stringaa.Text = aa;
if (isExit == false)
{
if (aa.Substring(0, 1) != "#") //群發(fā)為#,,沒有則為單發(fā)
{
aa
= aa.Insert(0, datareadwrite.client.Client.RemoteEndPoint.ToString() + "對大家說:");
//stringbb.Text = aa.Substring(1, aa.Length-1);
foreach (DataReadWrite drw in clientlist)
SendString(drw, aa);
}
else //私聊時截取ip地址,收到的信息為“#192.168.76.102:3315#消息”
{
int c=aa.LastIndexOf("#"); //截取ip地址的位置index
string ipaddress = aa.Substring(1, c - 1); //截取ip地址
for (int i = 0; i <= listBox1.Items.Count - 1; i++)
{
if (ipaddress == listBox1.Items[i].ToString())
{
//找到需要發(fā)送的對象
DataReadWrite obj = (DataReadWrite)clientlist[i];
//增加發(fā)送源的IP地址和端口號
aa = aa.Insert(c + 1, datareadwrite.client.Client.RemoteEndPoint.ToString() + "跟你說:");
SendString(obj, aa.Substring(c
+1));
break;
//MessageBox.Show(aa.Substring(c, aa.Length - 2));
}
}
}
datareadwrite.ns.BeginRead(datareadwrite.read,
0, datareadwrite.read.Length, ReadCallBack, datareadwrite);
}
}
catch (Exception e)
{
lst_ServerList.Invoke(setlistboxcallback, e.Message);
listBox1.Invoke(removelistboxcallback, datareadwrite);
comboBox1.Invoke(removecomboboxcallback, datareadwrite);
//SendList();
}
finally
{ }
}

//發(fā)送消息
private void SendString(DataReadWrite datareadwrite, string str)
{
try
{
datareadwrite.write
= Encoding.Unicode.GetBytes(str + "\r\n");
datareadwrite.ns.BeginWrite(datareadwrite.write,
0, datareadwrite.write.Length, new AsyncCallback(SendCallBack), datareadwrite);
datareadwrite.ns.Flush();
lst_ServerList.Invoke(setlistboxcallback,
string.Format("向{0}發(fā)送:{1}", datareadwrite.client.Client.RemoteEndPoint, str));
}
catch (Exception e)
{
lst_ServerList.Items.Add(e.Message);
//發(fā)送失敗時,,清除發(fā)送不成功的IP地址
listBox1.Invoke(removelistboxcallback, datareadwrite);
comboBox1.Invoke(removecomboboxcallback, datareadwrite);
//SendList();
}
finally
{
}
}

//發(fā)送回調(diào)
private void SendCallBack(IAsyncResult iar)
{
DataReadWrite datareadwrite
= (DataReadWrite)iar.AsyncState;
try
{
datareadwrite.ns.EndRead(iar);
}
catch (Exception e)
{
lst_ServerList.Invoke(setlistboxcallback, e.Message);
listBox1.Invoke(removelistboxcallback, datareadwrite);
comboBox1.Invoke(removecomboboxcallback, datareadwrite);
}
finally
{ }
}


//停止服務(wù)按鈕
private void btn_End_Click(object sender, EventArgs e)
{
isExit
= true;
allDone.Set();

btn_Start.Enabled
= true;
btn_End.Enabled
= false;

lst_ServerList.Items.Add(
"服務(wù)器于" + DateTime.Now.ToString() + "停止運行.");
}
回調(diào)函數(shù)實現(xiàn)
private void RemoveListBoxItems(DataReadWrite datareadwrite)
{
int index = clientlist.IndexOf(datareadwrite);
listBox1.Items.RemoveAt(index);
}

private void SetListBox(string str)
{
listBox1.Items.Add(str);
}

private void SetLbListBox(string str)
{
lst_ServerList.Items.Add(str);
lst_ServerList.SelectedIndex
= listBox1.Items.Count - 1;
lst_ServerList.ClearSelected();

}

private void RemoveComboBoxItems(DataReadWrite datareadwrite)
{
int index = clientlist.IndexOf(datareadwrite);
comboBox1.Items.RemoveAt(index);
}

private void SetComboBox(object obj)
{
comboBox1.Items.Add(obj);
}

 

再介紹一下DataReadWrite類,,這個類是實現(xiàn)將一個client的屬性和功能集成到一個類中,主要是負(fù)責(zé)處理數(shù)據(jù)的,,包括一個tcpclient對象,,

一個網(wǎng)絡(luò)流對象,2個負(fù)責(zé)讀寫的字節(jié)數(shù)組

 

DataReadWrite
public class DataReadWrite
{
public TcpClient client;
public NetworkStream ns;
public byte[] read;
public byte[] write;
public DataReadWrite(TcpClient client)
{
this.client = client;
ns
= client.GetStream();
read
= new byte[client.ReceiveBufferSize];
write
= new byte[client.SendBufferSize];
}

public void InitReadArray()
{
read
= new byte[client.ReceiveBufferSize];
}

public void InitWriteArray()
{
write
= new byte[client.SendBufferSize];
}

 

在構(gòu)造函數(shù)里得到連接上服務(wù)器的句柄,,包含服務(wù)器的IP地址信息,,從client對象上得到流對象,流對象就是用來在網(wǎng)絡(luò)上進行流的讀寫,。

 

 

以下是實現(xiàn)的截圖

嘗試了群發(fā)和私聊

 

由于是新手,,所以里面用詞方面可能有些不準(zhǔn)確,而且程序這是初成品,,還有很多方面的BUG,。例如退出時會發(fā)生異常,當(dāng)有人離開時,,列表不會更新,。

希望大家看了之后給點意見和建議,謝謝大家撒,。有空多留言,,謝謝

參考書籍:《visual c#網(wǎng)絡(luò)編程技術(shù)與實踐》和《c#網(wǎng)絡(luò)應(yīng)用高級編程》

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多