用C开发局域网聊天工具.docx
- 文档编号:15198052
- 上传时间:2023-07-02
- 格式:DOCX
- 页数:15
- 大小:17.94KB
用C开发局域网聊天工具.docx
《用C开发局域网聊天工具.docx》由会员分享,可在线阅读,更多相关《用C开发局域网聊天工具.docx(15页珍藏版)》请在冰点文库上搜索。
用C开发局域网聊天工具
用Socket开发局域网聊天工具(C#)
程序设计成为简单的服务端和客户端之间的通信,但通过一些方法可以将这两者进行统一起来,让服务端也成为客户端,让客户端也成为服务端,使它们之间可以互相随时不间断的通信.考虑到实现最原始的服务端和客户端之间的通信所需要的步骤对于写这样的程序是很有帮助的.
作为服务端,要声明一个SocketA并绑定(Bind)某一个IP+这个IP指定的通信端口,比如这个是127.0.0.1:
9050,然后开始监听(Listen),Listen可以监听来自多个IP传过来的连接请求,具体可以同时连接几个客户端,Listen方法中可以设定一个参数.如果Listen到某一个客户端发来连接请求了,这时定义一个新的SocketB专门负责与这个客户端的通信,SocketB=A.Accept().这时可以获取这个客户端的IP和端口,IPEndPointC=
(IPEndPoint)B.RemoteEndPoint,C.Address和C.Port分别表示客户端C的IP地址和端口.这时通过B.Send()方法就可以给C发送消息了,B.Receive()可以接收客户端C发来的信息.
作为客户端,也需要声明一个SocketD并绑定某一个IP+本机一个未被占用的端口,定义IPEndPointE表示要进行连接的服务端Socket,要指明E的IP和端口,这样才可以进行端口对端口之间的通信,接下来就可以尝试
D.Connect(E),连接成功之后就可以发送和接收数据了,D.Send(),D.Receive.发送消息时,数据都是以字节或字节数组为单位进行传输的,比如我客户端D要发送"HelloWorld"则要这样写:
D.Send(Encoding.ASCII.GetBytes("HelloWorld")).接受消息时,也是以字节或字节数组,比如服务端要接受D刚才发送的HelloWorld,可以这样写:
Byte[]data=newByte[1024];intreceivedDataLength=B.Receive(data);stringstringdata=Encoding.ASCII.GetString(data,0,
receivedDataLength);stringdata这时就是HelloWorld.
上面只是大概的阐述了服务端与客户端之间的通信过程,在网上找到了具体的代码例子,也贴过来参考参考.这个例子没有将服务端与客户端统一起来,他是分别写服务端和客户端的.
服务端:
usingSystem;
usingSystem;
usingSystem.Net;
usingSystem.Net.Sockets;
usingSystem.Text;
namespacetcpserver
{
///
///Class1的摘要说明。
///
classserver
{
///
///应用程序的主入口点。
///
[STAThread]
staticvoidMain(string[]args)
{
//
//TODO:
在此处添加代码以启动应用程序
//
intrecv;//用于表示客户端发送的信息长度
byte[]data;//=newbyte[1024];//用于缓存客户端所发送的信息,通过socket传递的信息必须为字节数组
IPEndPointipep=newIPEndPoint(IPAddress.Any,9050);//本机预使用的IP和端口
Socketnewsock=
newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
newsock.Bind(ipep);//绑定
newsock.Listen(10);//监听
Console.WriteLine("waitingforaclient");
Socketclient=newsock.Accept();//当有可用的客户端连接尝试时执行,并返回一个新的socket,用于与客户端之间的通信
IPEndPointclientip=(IPEndPoint)client.RemoteEndPoint;Console.WriteLine("connectwithclient:
"+clientip.Address+"atport:
"+clientip.Port);
stringwelcome="welcomehere!
";
data=Encoding.ASCII.GetBytes(welcome);
client.Send(data,data.Length,SocketFlags.None);//发送信息while(true)
{//用死循环来不断的从客户端获取信息
data=newbyte[1024];
recv=client.Receive(data);
Console.WriteLine("recv="+recv);
if(recv==0)//当信息长度为0,说明客户端连接断开
break;
Console.WriteLine(Encoding.ASCII.GetString(data,0,recv));client.Send(data,recv,SocketFlags.None);
}
Console.WriteLine("Disconnectedfrom"+clientip.Address);client.Close();
newsock.Close();
}
}
}
客户端:
usingSystem;
usingSystem.Net;
usingSystem.Net.Sockets;
usingSystem.Text;
namespacetcpclient
{
///
///Class1的摘要说明。
///
classclient
{
///
///应用程序的主入口点。
///
[STAThread]
staticvoidMain(string[]args)
{
//
//TODO:
在此处添加代码以启动应用程序
//
byte[]data=newbyte[1024];
Socketnewclient=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
newclient.Bind(newIPEndPoint(IPAddress.Any,905));
Console.Write("pleaseinputtheserverip:
");
stringipadd=Console.ReadLine();
Console.WriteLine();
Console.Write("pleaseinputtheserverport:
");
intport=Convert.ToInt32(Console.ReadLine());
IPEndPointie=newIPEndPoint(IPAddress.Parse(ipadd),port);//服务器的IP和端口
try
{
//因为客户端只是用来向特定的服务器发送信息,所以不需要绑定本机的IP和端口。
不需要监听。
newclient.Connect(ie);
}
catch(SocketExceptione)
{
Console.WriteLine("unabletoconnecttoserver");
Console.WriteLine(e.ToString());
return;
}
intreceivedDataLength=newclient.Receive(data);
stringstringdata=Encoding.ASCII.GetString(data,0,
receivedDataLength);
Console.WriteLine(stringdata);
while(true)
{
stringinput=Console.ReadLine();
if(input=="exit")
break;
newclient.Send(Encoding.ASCII.GetBytes(input));
data=newbyte[1024];
receivedDataLength=newclient.Receive(data);
stringdata=Encoding.ASCII.GetString(data,0,receivedDataLength);Console.WriteLine(stringdata);
}
Console.WriteLine("disconnectfromsercer");
newclient.Shutdown(SocketShutdown.Both);
newclient.Close();
}
}
}
上面的服务端和客户端都是控制台应用程序,想办法做一个窗体类型的,思路就是另起一个线程,这个线程专门负责两端建立连接.如果不采用另起线程的方法,当等待连接而没有连接上,或者主动连接,服务端还没有相应时,程序就会出现没有响应的假死状态.
当这个线程将两个端口连接成功后,就让程序进入一个死循环,这个死循环负责不断的接收是否有消息传来,传来的话就在txtGetMsg中显示出来:
while(true)//用死循环来不断的获取信息
{
data=newbyte[1024];
recv=newclient.Receive(data);
uiContext.Send(newSendOrPostCallback(
state=>
{
inttxtGetMsgLength=txtGetMsg.Text.Length;
stringrecMsg="Friend:
"+System.DateTime.Now.ToString()+"\n"+Encoding.Unicode.GetString(data,0,recv)+"\n";
txtGetMsg.AppendText(recMsg);
txtGetMsg.Select(txtGetMsgLength,recMsg.Length-
Encoding.Unicode.GetString(data,0,recv).Length-1);
txtGetMsg.SelectionColor=Color.Red;
}),null);
}
如果按下发送消息的按钮,则发送txtSendMsg中的文本,我写的是用Unicode编码,所以可以发送中文字符.
privatevoidbtnSendMsg_Click(objectsender,EventArgse){
stringinput=txtSendMsg.Text;
if(input=="")
{
MessageBox.Show("消息不能为空!
","发送消息出错");
txtSendMsg.Focus();
}
else
{
if(meIsClient)
{
newclient.Send(Encoding.Unicode.GetBytes(input));
stringshowText="Me:
"+System.DateTime.Now.ToString()+"\n"
+input+"\n";
inttxtGetMsgLength=txtGetMsg.Text.Length;
txtGetMsg.AppendText(showText);
txtGetMsg.Select(txtGetMsgLength,showText.Length-1-
input.Length);
txtGetMsg.SelectionColor=Color.Blue;
txtSendMsg.Text="";
}
else
{
client.Send(Encoding.Unicode.GetBytes(input));
stringshowText="Me"+System.DateTime.Now.ToString()+"\n"
+input+"\n";
inttxtGetMsgLength=txtGetMsg.Text.Length;
txtGetMsg.AppendText(showText);
txtGetMsg.Select(txtGetMsgLength,showText.Length-1-
input.Length);
txtGetMsg.SelectionColor=Color.Blue;
txtSendMsg.Text="";
}
}
}
下面是程序的所有代码:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.ComponentModel;
usingSystem.Data;
usingSystem.Drawing;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Windows.Forms;
usingSystem.Net;
usingSystem.Net.Sockets;
usingSystem.Threading;
namespaceChatting
{
publicpartialclassformMain:
Form
{
boolmeIsClient=true;
ThreadthreadAccess;
SynchronizationContextuiContext=null;
intrecv;//用于表示客户端发送的信息长度
byte[]data;//用于缓存客户端所发送的信息
IPEndPointipep=newIPEndPoint(IPAddress.Any,9050);//本机预使用的IP和端口
Socketnewsock=newSocket(AddressFamily.InterNetwork,
SocketType.Stream,ProtocolType.Tcp);
Socketnewclient=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
Socketclient;
IPEndPointclientip;
publicformMain()
{
InitializeComponent();
uiContext=WindowsFormsSynchronizationContext.Current;
}
privatevoidformMain_Load(objectsender,EventArgse)
{
btnSendMsg.Enabled=false;
txtIP.Focus();
}
privatevoidbtnSendMsg_Click(objectsender,EventArgse){
stringinput=txtSendMsg.Text;
if(input=="")
{
MessageBox.Show("消息不能为空!
","发送消息出错");
txtSendMsg.Focus();
}
else
{
if(meIsClient)
{
newclient.Send(Encoding.Unicode.GetBytes(input));
stringshowText="Me:
"+System.DateTime.Now.ToString()+"\n"
+input+"\n";
inttxtGetMsgLength=txtGetMsg.Text.Length;
txtGetMsg.AppendText(showText);
txtGetMsg.Select(txtGetMsgLength,showText.Length-1-
input.Length);
txtGetMsg.SelectionColor=Color.Blue;
txtSendMsg.Text="";
}
else
{
client.Send(Encoding.Unicode.GetBytes(input));
stringshowText="Me"+System.DateTime.Now.ToString()+"\n"
+input+"\n";
inttxtGetMsgLength=txtGetMsg.Text.Length;
txtGetMsg.AppendText(showText);
txtGetMsg.Select(txtGetMsgLength,showText.Length-1-
input.Length);
txtGetMsg.SelectionColor=Color.Blue;
txtSendMsg.Text="";
}
}
}
privatevoidbtnWaitAccess_Click(objectsender,EventArgse){
meIsClient=false;
threadAccess=newThread(newThreadStart(waitAccess));
threadAccess.Start();
label3.Text="等待对方连接...";
txtIP.Visible=false;
btnSureIP.Visible=false;
btnWaitAccess.Visible=false;
}
privatevoidbtnSureIP_Click(objectsender,EventArgse){
btnWaitAccess.Visible=false;
txtIP.Visible=false;
btnSureIP.Visible=false;
label3.Text="正在连接...";
threadAccess=newThread(newThreadStart(Access));
threadAccess.Start();
}
publicvoidwaitAccess()
{
newsock.Bind(ipep);//绑定
newsock.Listen(10);//监听个数
client=newsock.Accept();//当有可用的客户端连接尝试时执行,并返回一个新的socket,用于与客户端之间的通信
clientip=(IPEndPoint)client.RemoteEndPoint;
stringwelcome="连接建立成功";
uiContext.Send(newSendOrPostCallback(
state=>
{
toolStripLabel_IP.Text="对方IP:
"+
clientip.Address.ToString();//显示对方IP
toolStripLabel_Port.Text="对方端口:
"+
clientip.Port.ToString();//显示对方端口号
label3.Text=welcome;
btnSendMsg.Enabled=true;
txtSendMsg.Focus();
}
),null);
data=Encoding.Unicode.GetBytes(welcome);
client.Send(data,data.Length,SocketFlags.None);//发送确认接成功
while(true)//用死循环来不断的从客户端获取信息
{
data=newbyte[1024];
recv=client.Receive(data);
uiContext.Send(newSendOrPostCallback(
state=>
{
inttxtGetMsgLength=txtGetMsg.Text.Length;连stringrecMsg="Friend:
"+System.DateTime.Now.ToString()+"\n"+Encoding.Unicode.GetString(data,0,recv)+"\n";
txtGetMsg.AppendText(recMsg);
txtGetMsg.Select(txtGetMsgLength,recMsg.Length-
Encoding.Unicode.GetString(data,0,recv).Length-1);
txtGetMsg.SelectionColor=Color.Red;
}),null);
}
}
publicvoidAccess()
{
data=newbyte[1024];
newclient.Bind(newIPEndPoint(IPAddress.Any,9051));
stringipadd=txtIP.Text;
IPEndPointie=newIPEndPoint(IPAddress.Parse(ipadd),9050);//服务器的IP和端口
try
{
//因为客户端只是用来向特定的服务器发送信息,所以不需要绑定本机的IP和端口。
不需要监听。
newclient.Connect(ie);
}
catch(SocketExceptione)
{
MessageBox.Show(e.ToString(),"连接故障");
return;
}
intreceivedDataLength=newclient.Receive(data);
stringstringdata=Encoding.Unicode.GetString(data,0,
receivedDataLength);
uiContext.Send(newSendOrPostCallback(
state=>
{
toolStripLabel_IP.Text="对方IP:
"+txtIP.Text;//显示对方IPtoolStripLabel_Port.Text="对方端口:
9050";//显示对方端口号label3.Text=stringdata;
btnSendMsg.Enabled=
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 开发 局域网 聊天工具