日韩欧美人妻无码精品白浆,夜夜嗨AV免费入口,国产欧美官网在线看,高校回应聋哑女生因长相完美被质疑

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

C#局域網(wǎng)聊天工具、消息推送實現(xiàn)思路與源碼

admin
2016年12月23日 18:45 本文熱度 7577

C#局域網(wǎng)聊天工具怎么實現(xiàn)?

1. 網(wǎng)絡(luò)通訊編程的基礎(chǔ)便是協(xié)議,信息的發(fā)送常用的協(xié)議有面向連接的TCP協(xié)議,以及不面向連接的UDP協(xié)議

2. TCP:TransmissionControlProtocol傳輸控制協(xié)議,其是一種面向連接的、可靠的字節(jié)流服

務(wù)。面向連接意味著兩個使用TCP的應(yīng)用(通常是一個客戶和一個服務(wù)器)在彼此交換數(shù)據(jù)之前必須先建立一個TCP連接。這一過程與打電話很相似,先撥號振鈴,等待對方摘機說“喂”,然后才說明是誰。

3. UDP:UserDatagramProtocol用戶數(shù)據(jù)報協(xié)議(RFC768),UDP傳送數(shù)據(jù)前并不與對方建立連

接,即UDP是無連接的,在傳輸數(shù)據(jù)前,發(fā)送方和接收方相互交換信息使雙方同步。

4. 系統(tǒng)也要定義自己的通訊協(xié)議,來完成一些系統(tǒng)的功能,如用戶上,下線的通知,都要定義

自己的通訊協(xié)議來完成相應(yīng)的功能!也可以稱這種自定義的協(xié)議為“命令”.

5. 下面以著名的飛鴿傳書為例,說明其自定義的協(xié)議(命令)

IPMSG_NOOPERATION不進(jìn)行任何操作

IPMSG_BR_ENTRY用戶上線

IPMSG_BR_EXIT用戶退出

IPMSG_ANSENTRY通報在線

IPMSG_SENDMSG發(fā)送消息

IPMSG_RECVMSG通報收到消息

IPMSG_GETFILEDATA請求通過TCP傳輸文件

IPMSG_RELEASEFILES停止接收文件

IPMSG_GETDIRFILES請求傳輸文件夾以“IPMSG_BR_ENTRY用戶上線”和“IPMSG_ANSENTRY通報在線”為例說明命令處理流程:當(dāng)程序啟動時,命令I(lǐng)PMSG_BR_ENTRY被廣播到網(wǎng)絡(luò)中,向所有在線的用戶提示一個新用戶的到達(dá)(即表示“我來了”);所有在線用戶將把該新上線用戶添加到自己的用戶列表中,并向該新上線用戶發(fā)送IPMSG_ANSENTRY命令(即表示“我在線”);該新上線用戶接收到IPMSG_ANSENTRY命令后即將在線用戶添加到自己的用戶列表中。

PS:根據(jù)本系統(tǒng)的特征,可以在聊天部分采用UDP協(xié)議,在文件傳輸,視頻,語音功能上采用TCP協(xié)議

6. 程序啟動就要發(fā)送廣播消息,如何發(fā)送廣播消息,以及C#如何實現(xiàn)廣播.

第一部分.什么是廣播地址,以及廣播地址怎么計算

1.1廣播地址是什么?

主機號全為1,用于向一個網(wǎng)絡(luò)內(nèi)的所有主機發(fā)送信息的IP地址.如:受限的廣播地址是255.255.255.255。該地址用于主機配置過程中IP數(shù)據(jù)報的目的地址,此時,主機可能還不知道它所在網(wǎng)絡(luò)的網(wǎng)絡(luò)掩碼,甚至連它的IP地址也不知道。在任何情況下,路由器都不轉(zhuǎn)發(fā)目的地址為受限的廣播地址的數(shù)據(jù)報,這樣的數(shù)據(jù)報僅出現(xiàn)在本地網(wǎng)絡(luò)中。

PS:一般無特殊要求廣播地址選擇255.255.255.255即可.

1.2計算方法

首先計算網(wǎng)絡(luò)地址=IP地址邏輯與(&)子網(wǎng)掩碼

先把IP,子網(wǎng)掩碼轉(zhuǎn)為2進(jìn)制,然后進(jìn)行邏輯與運算,得出網(wǎng)絡(luò)地址

例:

IP192.168.1.3子網(wǎng)掩碼255.255.0.0

IP轉(zhuǎn)二進(jìn)制11000000.10100100.00000001.00000011

子網(wǎng)掩碼11111111.11111111.00000000.00000000

與運算后11000000.10100100.00000000.00000000

192.168.0.0這就是網(wǎng)絡(luò)地址,其中子網(wǎng)掩碼全1對應(yīng)為網(wǎng)絡(luò)號,全0對應(yīng)的是主機號,即192.168.0.0對應(yīng)的網(wǎng)絡(luò)號為192.168,主機號為0.0.將網(wǎng)絡(luò)地址主機部分全取反后得到的地址便是廣播地址:

廣播地址11000000.10100100.11111111.11111111

換成10進(jìn)制則為192.168.0.0

第二部分.C#利用UDP協(xié)議如何實現(xiàn)廣播

2.1如何實現(xiàn)UDP廣播,直接舉例說明:

button1_Click時使用了UDP廣播向外發(fā)送了數(shù)據(jù)

RecData()在后臺接受UDP協(xié)議的消息

//UDP通過廣播實現(xiàn)群發(fā)功能

namespace BroadcastExample

{

public partial class Form1:Form

{

delegate void AppendStringCallback(stringtext);

AppendStringCallback appendstringcallback;

//使用的接收端口51008

///<summary>

///端口號

///</summary>

private int port=51008;

///<summary>

///udp連接對象

///</summary>

private UdpClient udpclient;

public Form1()

{

InitializeComponent();

appendstringcallback = new AppendStringCallback(AppendString);

}

///<summary>

///委托對象的處理過程

///</summary>

///<paramname="text"></param>

private void AppendString(stringtext)

{

if(richtextBox2.InvokeRequired==true)

{

this.Invoke(appendstringcallback,text);

}

else

{

richtextBox2.AppendText(text+"\r\n");

}

}

///<summary>

///在后臺運行的接收線程

///</summary>

private void RecData()

{

//本機指定端口接收

udpclient=new UdpClient(port);

IPEndPoint remote=null;

//接收從遠(yuǎn)程主機發(fā)送過來的信息

while(true)

{

try

{

//關(guān)閉udpclient時此句會產(chǎn)生異常

byte[]bytes=udpclient.Receive(refremote);

stringstr=Encoding.UTF8.GetString(bytes,0,bytes.Length);

AppendString(string.Format("來自{0}:{1}",remote,str));

}

catch

{

//退出循環(huán),結(jié)束線程

break;

}

}

}

privatevoidForm1_Load(objectsender,EventArgse)

{

//創(chuàng)建一個線程接收接收遠(yuǎn)程主機發(fā)來的信息

Thread mythread=new Thread(new ThreadStart(RecData));

//將線程設(shè)為后臺運行

mythread.IsBackground=true;

mythread.Start();

}

private void Form1_FormClosing(objectsender,FormClosingEventArgse)

{

udpclient.Close();

}

private void button1_Click(objectsender,EventArgse)

{

UdpClient myUdpclient=newUdpClient();

try

{

IPEndPoint iep=new IPEndPoint(IPAddress.Broadcast,port);

byte[]bytes=System.Text.Encoding.UTF8.GetBytes(textBox1.Text);

myUdpclient.Send(bytes,bytes.Length,iep);

textBox1.Clear();

myUdpclient.Close();

textBox1.Focus();

}

catch(Exceptionerr)

{

MessageBox.Show(err.Message,"發(fā)送失敗");

}

finally

{

myUdpclient.Close();

}

}

}

}

啟動主程序時,同時啟動UDP的監(jiān)聽,這時應(yīng)該使用集合來做為消息隊列的緩存,以便用戶能在任何時候瀏覽到消息.這個集合一般在主程序中定義,而用戶接受消息,一般我們會彈出窗口給用戶來瀏覽消息,以及在新窗口中回復(fù)消息,那如何將主窗口中的消息,傳遞到消息顯示窗體中呢?

如何是Web(ASP.net)我們可以封裝到form中傳值,或者request傳值,甚至可以在URL中接參數(shù)直接傳值,而winform中窗體傳值以上方法就都不在能用了.

在windowsform之間傳值,我總結(jié)了有四個方法:全局變量、屬性、窗體構(gòu)造函數(shù)和delegate。 第一個全局變量:

這個最簡單,只要把變量描述成static就可以了,在form2中直接引用form1的變量,代碼如下: 在form1中定義一個static變量publicstaticinti=9;

Form2中的鈕扣按鈕如下:

privatevoidbutton1_Click(objectsender,System.EventArgse)

{

textBox1.Text=Form1.i.ToString();

}

第二個方法是利用屬性:

假設(shè)我們需要點擊主窗體FMMain中的某一個按鈕時打開子窗體FMChild并將某一個值傳給子窗體FMChild,一般情況下,我們點擊按鈕顯示子窗體FMChild的代碼為: FMChildfmChild=newFMChild();fmChild.ShowDialog();fmChild.Dispose();

如果我們需要將主窗體FMMain中的stringstrValueA的值傳給FMChild,那么我們首先對strValueA進(jìn)行如下處理:

privatestringstrValueA;publicstringStrValueA{get{returnstrValueA;}set{strValueA=value;}}

使其成為主窗體FMMain的一個屬性,接著修改顯示子窗體的代碼為以下兩種的其中一種。 方法一:

FMChildfmChild=newFMChild();fmChild.ShowDialog(this);fmChild.Dispose(); 方法二:

FMChildfmChild=newFMChild();FMChild.Owner=this;fmChild.ShowDialog();fmChild.Dispose();

然后在修改子窗體FMChild中申明一個主窗體FMMain對象,

FMMainfmMain;

在需要使用主窗體FMMain的stringstrValueA的地方加上如下代碼:

fmMain=(FMMain)this.Owner;

這樣,就可以獲得主窗體FMMain中strValueA的值了。

這時,如果你需要將子窗體FMChild中的stringstrValueB傳給主窗體FMMain,同樣處理stringstrValueB.

privatestringstrValueB;publicstringStrValueB{get{returnstrValueB;}set{strValueB=value;}}

那么你在關(guān)閉子窗體代碼fmChild.Dispose();后,可以寫一些代碼來保存或者處理FMChild的strValueB,例如:

stringstrTmp=fmChild.StrValueB;

第三個方法是用構(gòu)造函數(shù):

Form1的button按鈕這樣寫:

privatevoidbutton1_Click(objectsender,System.EventArgse)

{

Form2temp=newForm2(9);

temp.Show();

}

Form2的構(gòu)造函數(shù)這樣寫:

publicForm2(inti)

{

InitializeComponent();

textBox1.Text=i.ToString();

}

第四個方法是用delegate,代碼如下:

Form2中先定義一個delegate

publicdelegatevoidreturnvalue(inti);

publicreturnvalueReturnValue;

form2中的button按鈕代碼如下:

privatevoidbutton1_Click(objectsender,System.EventArgse)

{

if(ReturnValue!=null)

ReturnValue(8);

}

Form1中的button按鍵如下:

privatevoidbutton1_Click(objectsender,System.EventArgse)

{

Form2temp=newForm2();

temp.ReturnValue=newtemp.Form2.returnvalue(showvalue);

temp.Show();

}

privatevoidshowvalue(inti)

{

textBox1.Text=i.ToString();

}

點擊form2的button,form1中的textbox中的值就會相應(yīng)變化。

在這四個方法中,

第一個是雙向傳值,也就是說,form1和form2改變i的值,另一方也會受到影響。 第二個方法可以單向也可以雙向傳值。

第三個方法是form1->form2單向傳值。

第四個方法是form2->form1單向傳值。

現(xiàn)在很多程序都有托盤功能,而我們的聊天工具更是如此,無論是QQ,旺旺,飛鴿傳書等等,都是

以托盤的形式工作在后臺,對消息進(jìn)行監(jiān)聽的.而VS2005給我們提供了現(xiàn)成的控件,來完成托盤的功能,下面我結(jié)合代碼講解下項目中可能用到的托盤技巧.

1.如何實現(xiàn)托盤功能:

在VS2005中直接添加notifyIcon控件,然后設(shè)置下icon屬性,給其設(shè)置個圖標(biāo)即可,使用托盤功能. 但是托盤并不能實現(xiàn)我們要求的功能,具體的功能實現(xiàn),需要我們手工添加代碼實現(xiàn).

2.如何最小化時自動到托盤

private void Form1_Resize(objectsender,System.EventArgse)

{

if(this.WindowState==FormWindowState.Minimized)

{

this.Visible=false;

this.notifyIcon1.Visible=true;

}

}

3.如何雙擊托盤恢復(fù)原狀

private void notifyIcon1_Click(objectsender,System.EventArgse)

{

this.Visible=true;

this.WindowState=FormWindowState.Normal;

this.notifyIcon1.Visible=false;

}

4.實現(xiàn)托盤的閃爍功能(如QQ有消息時的閃爍)

(1).首先我們在空白窗體中拖入一個NotifyIcon控件和定時控件

privateSystem.Windows.Forms.NotifyIconnotifyIcon1;

privateSystem.Windows.Forms.Timertimer1;

(2).其次,我們準(zhǔn)備兩張ico圖片,用來顯示在任務(wù)欄,其中一張可用透明的ico圖片,分別叫做1.ico和2.ico;并且建立兩個icon對象分別用來存放兩個ico圖片;

privateIconico1=newIcon("1.ico");

privateIconico2=newIcon("2.ICO");//透明的圖標(biāo)

(3).在Form_load中初始化notifyicon:

privatevoidForm1_Load(objectsender,System.EventArgse)

{

this.notifyIcon1.Icon=ico1;//設(shè)置程序剛運行時顯示在任務(wù)欄的圖標(biāo)

this.timer1.Enable=true;//將定時控件設(shè)為啟用,默認(rèn)為false;

}

(4).先設(shè)置一個全局變量i,用來控制圖片索引,然后創(chuàng)建定時事件,雙擊定時控件就可以編輯 inti=0;

privatevoidtimer1_Tick(objectsender,System.EventArgse)

{

//如果i=0則讓任務(wù)欄圖標(biāo)變?yōu)橥该鞯膱D標(biāo)并且退出

if(i<1)

{

this.notifyIcon1.Icon=ico2;

i++;

return;

}

//如果i!=0,就讓任務(wù)欄圖標(biāo)變?yōu)閕co1,并將i置為0;

else

i=0;

}

由于消息傳輸要求較低,而且為了簡化聊天的步驟,在局域網(wǎng)聊天中,采用UDP是非常好的選擇.因為UDP可以不用連接,在獲取用戶列表后,直接點擊用戶名就可以發(fā)送消息,減少了等待連接等繁瑣

1.UDP發(fā)送信息

namespaceXChat.SendMes

{

public class MsgSend

{

private UdpClient udp=null;

private int PORT;

private IPEndPoint endP=null;

public MsgSend()

{

this.PORT=58888;

}

publicMsgSend(intport)

{

this.PORT=port;

}

///<summary>

///發(fā)送信息

///</summary>

///<paramname="hostName">要發(fā)送到的主機名</param>

///<paramname="message">要發(fā)送的信息</param>

publicvoidSendMessage(stringhostName,stringmessage)

{

this.udp=newUdpClient();

endP=newIPEndPoint(Dns.GetHostEntry(hostName).AddressList[0],PORT);

try

{

//byte[]b=Encoding.ASCII.GetBytes(hostName);

byte[]b=Encoding.UTF8.GetBytes(message);

udp.Send(b,b.Length,endP);

}

catch

{

System.Windows.Forms.MessageBox.Show("發(fā)送出錯!");

}

finally

{

this.udp.Close();

}

}

}

}

要使用時直接new MsgSend().SendMessage(主機名,消息);

2.UDP接收消息

namespaceXChat.SendMes

{

//設(shè)置消息到前臺的委托

public delegate voidSet Message(stringmes);

public class MsgRecive

{

private int PORT;

private UdpClient udp=null;

private Thread recThread=null;

private IPEndPoint ipep=null;

private SetMessages etMes;

public MsgRecive()

{

this.PORT=58888;

}

publicMsgRecive(intport)

{

this.PORT=port;

}

///<summary>

///開啟后臺接受消息線程

///</summary>

///<paramname="setMes">傳入設(shè)置消息的委托</param>

publicvoidStartReciveMsg(SetMessagesetMes)

{

this.setMes=setMes;

udp=newUdpClient(PORT);

recThread=newThread(newThreadStart(ReciveMsg));

recThread.Start();

}

///<summary>

///關(guān)閉后臺消息接收線程

///</summary>

publicvoidCloseReciveMsg()

{

recThread.Abort();

//recThread.Join();

udp.Close();

}

privatevoidReciveMsg()

{

while(true)

//這句很重要,否則CPU很容易100%

Thread.Sleep(500);

byte[] b = udp.Receive(refipep);

string message=Encoding.UTF8.GetString(b,0,b.Length);

this.setMes(message);

}

}

}

}

在前臺private MsgRecive mr=null;

public xchatFrm()

{

??

this.mr=newMsgRecive(port);

this.mr.StartReciveMsg(newSetMessage(GetMes));

??

}

這幾天一直想寫一個類似QQ文件發(fā)送的東西,上網(wǎng)找了一些資料,都不是很理想,下面我把我的思路和基本實現(xiàn)代碼說下。

為了把問題說清楚,把一些變量都直接附值了,并沒有通過輸入附值

private string path = "F:\\SmartMovie.EXE"; //要發(fā)送的文件

private Socket s;

private void listen()

{

string ip = "127.0.0.1"; //遠(yuǎn)程IP 這里定義為自己的機器

IPAddress[] ih = Dns.GetHostAddresses(ip); //獲得IP列表

IPAddress newip = ih[0]; //獲取IP地址

int port = 6789; //定義端口

IPEndPoint Conncet = new IPEndPoint(newip, port); //構(gòu)造結(jié)點

s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //初始化socket

try

{

s.Connect(Conncet); //連接遠(yuǎn)程服務(wù)器

if (s.Connected) //如果連接成功 s.Connected 則為true 否則為 false

{

Thread t = new Thread(new ThreadStart(set)); //創(chuàng)建進(jìn)程

t.Start(); //開始進(jìn)程

Console.WriteLine("發(fā)送完畢")

}

}

catch(NullReferenceException e)

{

Console.WriteLine("{0}",e);

}

private void set() //創(chuàng)建set函數(shù)

{

Console.WriteLine("開始發(fā)送數(shù)據(jù)");

byte[] b = new byte[10000000]; //創(chuàng)建文件緩沖區(qū),這里可以認(rèn)為文件的最大值

FileStream file = File.Open(path, FileMode.Open,FileAccess.Read); //創(chuàng)建文件流

int start = 0;

int end = (int)file.Length; //獲取文件長度 文件傳送如果有需要超過int的范圍估計就要改寫FileStream類了

try

{

while (end != 0)

{

int count = file.Read(b, start, end); //把數(shù)據(jù)寫進(jìn)流 start += count;

end -= count;

}

while (start != 0)

{

int n = s.Send(b, end, start, SocketFlags.None); //用Socket的Send方法發(fā)送流

end += n;

start -= n;

}

file.Close(); //關(guān)閉文件流

s.Close(); //關(guān)閉Socket

}

catch (NullReferenceException e)

{

Console.WriteLine("{0}", e);

}

這樣文件發(fā)送的模型就實現(xiàn)了

接下去實現(xiàn)文件的接收,首先要確定對方發(fā)送文件的長度,其實上面的那段還要加入發(fā)送文件長度的功能,實現(xiàn)很簡單,就是發(fā)送int變量end ,然后要求接收代碼返回一個Boolean確定是否發(fā)送,這里為了更簡明的說清楚原理并沒有實現(xiàn)

private void get()

{

string path = "G:\\da.exe"; //接收的文件

FileStream file = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write); //寫入文件流

TcpListener listen = new TcpListener(6789); //監(jiān)聽端口

Socket s1 = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //定義Socket并初始化

try

{

listen.Start(); //開始監(jiān)聽

s1 = listen.AcceptSocket(); //獲取Socket連接

byte[] data = new byte[10000000]; //定義緩沖區(qū)

int longer = data.Length;

int start = 0;

int mid = 0;

if (s1.Connected) //確定連接

{

Console.WriteLine("連接成功");

int count = s1.Receive(data, start, longer, SocketFlags.None); //把接收到的byte存入緩沖區(qū)

mid += count;

longer -= mid;

while (count != 0)

{

count = s1.Receive(data, mid, longer, SocketFlags.None);

mid += count;

longer -= mid;

}

file.Write(data, 0, 1214134); //寫入文件,1214134為文件大小,可以用socket發(fā)送獲得,代碼前面已經(jīng)說明。

s1.Close();

file.Close();

}

}

catch(NullReferenceException e)

{

Console.WriteLine("{0}",e);

}

}


該文章在 2016/12/23 18:45:29 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點晴ERP是一款針對中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點晴PMS碼頭管理系統(tǒng)主要針對港口碼頭集裝箱與散貨日常運作、調(diào)度、堆場、車隊、財務(wù)費用、相關(guān)報表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點,圍繞調(diào)度、堆場作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點晴WMS倉儲管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務(wù)都免費,不限功能、不限時間、不限用戶的免費OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved