狠狠色丁香婷婷综合尤物/久久精品综合一区二区三区/中国有色金属学报/国产日韩欧美在线观看 - 国产一区二区三区四区五区tv

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

C#局域網聊天工具、消息推送實現思路與源碼

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

C#局域網聊天工具怎么實現?

1. 網絡通訊編程的基礎便是協議,信息的發送常用的協議有面向連接的TCP協議,以及不面向連接的UDP協議

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

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

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

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

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

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

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

IPMSG_NOOPERATION不進行任何操作

IPMSG_BR_ENTRY用戶上線

IPMSG_BR_EXIT用戶退出

IPMSG_ANSENTRY通報在線

IPMSG_SENDMSG發送消息

IPMSG_RECVMSG通報收到消息

IPMSG_GETFILEDATA請求通過TCP傳輸文件

IPMSG_RELEASEFILES停止接收文件

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

PS:根據本系統的特征,可以在聊天部分采用UDP協議,在文件傳輸,視頻,語音功能上采用TCP協議

6. 程序啟動就要發送廣播消息,如何發送廣播消息,以及C#如何實現廣播.

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

1.1廣播地址是什么?

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

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

1.2計算方法

首先計算網絡地址=IP地址邏輯與(&)子網掩碼

先把IP,子網掩碼轉為2進制,然后進行邏輯與運算,得出網絡地址

例:

IP192.168.1.3子網掩碼255.255.0.0

IP轉二進制11000000.10100100.00000001.00000011

子網掩碼11111111.11111111.00000000.00000000

與運算后11000000.10100100.00000000.00000000

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

廣播地址11000000.10100100.11111111.11111111

換成10進制則為192.168.0.0

第二部分.C#利用UDP協議如何實現廣播

2.1如何實現UDP廣播,直接舉例說明:

button1_Click時使用了UDP廣播向外發送了數據

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

//UDP通過廣播實現群發功能

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;

//接收從遠程主機發送過來的信息

while(true)

{

try

{

//關閉udpclient時此句會產生異常

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

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

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

}

catch

{

//退出循環,結束線程

break;

}

}

}

privatevoidForm1_Load(objectsender,EventArgse)

{

//創建一個線程接收接收遠程主機發來的信息

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

//將線程設為后臺運行

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,"發送失敗");

}

finally

{

myUdpclient.Close();

}

}

}

}

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

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

在windowsform之間傳值,我總結了有四個方法:全局變量、屬性、窗體構造函數和delegate。 第一個全局變量:

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

Form2中的鈕扣按鈕如下:

privatevoidbutton1_Click(objectsender,System.EventArgse)

{

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

}

第二個方法是利用屬性:

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

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

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;}}

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

stringstrTmp=fmChild.StrValueB;

第三個方法是用構造函數:

Form1的button按鈕這樣寫:

privatevoidbutton1_Click(objectsender,System.EventArgse)

{

Form2temp=newForm2(9);

temp.Show();

}

Form2的構造函數這樣寫:

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中的值就會相應變化。

在這四個方法中,

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

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

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

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

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

1.如何實現托盤功能:

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

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

private void Form1_Resize(objectsender,System.EventArgse)

{

if(this.WindowState==FormWindowState.Minimized)

{

this.Visible=false;

this.notifyIcon1.Visible=true;

}

}

3.如何雙擊托盤恢復原狀

private void notifyIcon1_Click(objectsender,System.EventArgse)

{

this.Visible=true;

this.WindowState=FormWindowState.Normal;

this.notifyIcon1.Visible=false;

}

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

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

privateSystem.Windows.Forms.NotifyIconnotifyIcon1;

privateSystem.Windows.Forms.Timertimer1;

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

privateIconico1=newIcon("1.ico");

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

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

privatevoidForm1_Load(objectsender,System.EventArgse)

{

this.notifyIcon1.Icon=ico1;//設置程序剛運行時顯示在任務欄的圖標

this.timer1.Enable=true;//將定時控件設為啟用,默認為false;

}

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

privatevoidtimer1_Tick(objectsender,System.EventArgse)

{

//如果i=0則讓任務欄圖標變為透明的圖標并且退出

if(i<1)

{

this.notifyIcon1.Icon=ico2;

i++;

return;

}

//如果i!=0,就讓任務欄圖標變為ico1,并將i置為0;

else

i=0;

}

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

1.UDP發送信息

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>

///發送信息

///</summary>

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

///<paramname="message">要發送的信息</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("發送出錯!");

}

finally

{

this.udp.Close();

}

}

}

}

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

2.UDP接收消息

namespaceXChat.SendMes

{

//設置消息到前臺的委托

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">傳入設置消息的委托</param>

publicvoidStartReciveMsg(SetMessagesetMes)

{

this.setMes=setMes;

udp=newUdpClient(PORT);

recThread=newThread(newThreadStart(ReciveMsg));

recThread.Start();

}

///<summary>

///關閉后臺消息接收線程

///</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文件發送的東西,上網找了一些資料,都不是很理想,下面我把我的思路和基本實現代碼說下。

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

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

private Socket s;

private void listen()

{

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

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

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

int port = 6789; //定義端口

IPEndPoint Conncet = new IPEndPoint(newip, port); //構造結點

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

try

{

s.Connect(Conncet); //連接遠程服務器

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

{

Thread t = new Thread(new ThreadStart(set)); //創建進程

t.Start(); //開始進程

Console.WriteLine("發送完畢")

}

}

catch(NullReferenceException e)

{

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

}

private void set() //創建set函數

{

Console.WriteLine("開始發送數據");

byte[] b = new byte[10000000]; //創建文件緩沖區,這里可以認為文件的最大值

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

int start = 0;

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

try

{

while (end != 0)

{

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

end -= count;

}

while (start != 0)

{

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

end += n;

start -= n;

}

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

s.Close(); //關閉Socket

}

catch (NullReferenceException e)

{

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

}

這樣文件發送的模型就實現了

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

private void get()

{

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

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

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

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

try

{

listen.Start(); //開始監聽

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

byte[] data = new byte[10000000]; //定義緩沖區

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存入緩沖區

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發送獲得,代碼前面已經說明。

s1.Close();

file.Close();

}

}

catch(NullReferenceException e)

{

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

}

}


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