用Socket做一个局域网聊天工具(转)
原文:http://www.cnblogs.com/technology/archive/2010/08/15/1799858.html
程序设计成为简单的服务端和客户端之间的通信, 但通过一些方法可以将这两者进行统一起来, 让服务端也成为客户端, 让客户端也成为服务端, 使它们之间可以互相随时不间断的通信. 考虑到实现最原始的服务端和客户端之间的通信所需要的步骤对于写这样的程序是很有帮助的.
作为服务端, 要声明一个Socket A并绑定(Bind)某一个IP+这个IP指定的通信端口, 比如这个是127.0.0.1:9050, 然后开始监听(Listen), Listen可以监听来自多个IP传过来的连接请求, 具体可以同时连接几个客户端, Listen方法中可以设定一个参数. 如果Listen到某一个客户端发来连接请求了, 这时定义一个新的Socket B专门负责与这个客户端的通信, Socket B = A.Accept(). 这时可以获取这个客户端的IP和端口, IPEndPoint C = (IPEndPoint)B.RemoteEndPoint, C.Address和C.Port分别表示客户端C的IP地址和端口. 这时通过B.Send()方法就可以给C发送消息了, B.Receive()可以接收客户端C发来的信息.
作为客户端, 也需要声明一个Socket D并绑定某一个IP+本机一个未被占用的端口, 定义IPEndPoint E表示要进行连接的服务端Socket, 要指明E的IP和端口, 这样才可以进行端口对端口之间的通信, 接下来就可以尝试D.Connect(E), 连接成功之后就可以发送和接收数据了, D.Send(), D.Receive.
发送消息时, 数据都是以字节或字节数组为单位进行传输的, 比如我客户端D要发送"Hello World"则要这样写: D.Send(Encoding.ASCII.GetBytes("Hello World")). 接受消息时, 也是以字节或字节数组, 比如服务端要接受D刚才发送的Hello World, 可以这样写: Byte[] data = new Byte[1024]; int receivedDataLength = B.Receive(data); string stringdata = Encoding.ASCII.GetString(data, 0, receivedDataLength); stringdata这时就是Hello World.
上面只是大概的阐述了服务端与客户端之间的通信过程, 在网上找到了具体的代码例子, 也贴过来参考参考. 这个例子没有将服务端与客户端统一起来, 他是分别写服务端和客户端的.
服务端代码
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
using System;using System;using System.Net;using System.Net.Sockets;using System.Text;namespace tcpserver{ /// <summary> /// Class1 的摘要说明。 /// </summary> class server { /// <summary> /// 应用程序的主入口点。 /// </summary> [STAThread] static void Main( string [] args) { // // TODO: 在此处添加代码以启动应用程序 // int recv; // 用于表示客户端发送的信息长度 byte [] data;// = new byte [ 1024 ]; // 用于缓存客户端所发送的信息,通过socket传递的信息必须为字节数组 IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050 ); // 本机预使用的IP和端口 Socket newsock = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); newsock.Bind(ipep); // 绑定 newsock.Listen( 10 ); // 监听 Console.WriteLine( " waiting for a client " ); Socket client = newsock.Accept(); //当有可用的客户端连接尝试时执行,并返回一个新的socket,用于与客户端之间的通信 IPEndPoint clientip = (IPEndPoint)client.RemoteEndPoint; Console.WriteLine( " connect with client: " + clientip.Address + " at port: " + clientip.Port); string welcome = " welcome here! " ; data = Encoding.ASCII.GetBytes(welcome); client.Send(data,data.Length,SocketFlags.None); // 发送信息 while ( true ) { // 用死循环来不断的从客户端获取信息 data = new byte [ 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( " Disconnected from " + clientip.Address); client.Close(); newsock.Close(); } }} |
客户端代码
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
using System;using System.Net;using System.Net.Sockets;using System.Text;namespace tcpclient{ /// <summary> /// Class1 的摘要说明。 /// </summary> class client { /// <summary> /// 应用程序的主入口点。 /// </summary> [STAThread] static void Main(string[] args) { // // TODO: 在此处添加代码以启动应用程序 // byte[] data = new byte[1024]; Socket newclient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); newclient.Bind(new IPEndPoint(IPAddress.Any, 905)); Console.Write(" please input the server ip: "); string ipadd = Console.ReadLine(); Console.WriteLine(); Console.Write(" please input the server port: "); int port = Convert.ToInt32(Console.ReadLine()); IPEndPoint ie = new IPEndPoint(IPAddress.Parse(ipadd), port); // 服务器的IP和端口 try { // 因为客户端只是用来向特定的服务器发送信息,所以不需要绑定本机的IP和端口。不需要监听。 newclient.Connect(ie); } catch (SocketException e) { Console.WriteLine(" unable to connect to server "); Console.WriteLine(e.ToString()); return; } int receivedDataLength = newclient.Receive(data); string stringdata = Encoding.ASCII.GetString(data, 0, receivedDataLength); Console.WriteLine(stringdata); while (true) { string input = Console.ReadLine(); if (input == " exit ") break; newclient.Send(Encoding.ASCII.GetBytes(input)); data = new byte[1024]; receivedDataLength = newclient.Receive(data); stringdata = Encoding.ASCII.GetString(data, 0, receivedDataLength); Console.WriteLine(stringdata); } Console.WriteLine(" disconnect from sercer "); newclient.Shutdown(SocketShutdown.Both); newclient.Close(); } }} |
上面的服务端和客户端都是控制台应用程序, 想办法做一个窗体类型的, 思路就是另起一个线程, 这个线程专门负责两端建立连接. 如果不采用另起线程的方法, 当等待连接而没有连接上, 或者主动连接, 服务端还没有相应时, 程序就会出现没有响应的假死状态.
当这个线程将两个端口连接成功后, 就让程序进入一个死循环, 这个死循环负责不断的接收是否有消息传来, 传来的话就在txtGetMsg中显示出来:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
while (true) // 用死循环来不断的获取信息{ data = new byte[1024]; recv = newclient.Receive(data); uiContext.Send(new SendOrPostCallback( state => { int txtGetMsgLength = txtGetMsg.Text.Length; string recMsg = "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编码, 所以可以发送中文字符.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
private void btnSendMsg_Click(object sender, EventArgs e){ string input = txtSendMsg.Text; if (input == "") { MessageBox.Show("消息不能为空!", "发送消息出错"); txtSendMsg.Focus(); } else { if (meIsClient) { newclient.Send(Encoding.Unicode.GetBytes(input)); string showText = "Me: " + System.DateTime.Now.ToString() + "\n " + input + "\n"; int txtGetMsgLength = 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)); string showText = "Me " + System.DateTime.Now.ToString() + "\n " + input + "\n"; int txtGetMsgLength = txtGetMsg.Text.Length; txtGetMsg.AppendText(showText); txtGetMsg.Select(txtGetMsgLength, showText.Length - 1 - input.Length); txtGetMsg.SelectionColor = Color.Blue; txtSendMsg.Text = ""; } }} |
程序的运行效果

用Socket做一个局域网聊天工具(转)的更多相关文章
- 用c#写的一个局域网聊天客户端 类似小飞鸽
用c#写的一个局域网聊天客户端 类似小飞鸽 摘自: http://www.cnblogs.com/yyl8781697/archive/2012/12/07/csharp-socket-udp.htm ...
- Python使用Socket写一个简单聊天程序
b2b模式的聊天工具 服务端: # 链接 while True: print('等待连接...') sock,adr = server_socket.accept() while True: try: ...
- 通过socket和Udp协议简单实现一个群体聊天工具(控制台)
编写一个聊天程序.有收数据的部分 和 发数据的部分.这两个部分需要同时执行,这就用到多线程技术,一个线程负责收,一个现象负责发. 因为收和发动作是不一致的,所以要定义两个run方法而且这两个方法要封装 ...
- nodeJS+express+Jade写一个局域网聊天应用(node基础)
为了复习一下nodeJS, 而且socketIO这东西听起来就好高端有木有, 而且有人写过了open, 也可以作为自己的参考有木有, 点击下载源代码: express是4.x的版本, 跟以前的配置有些 ...
- 使用socket搭建一个网络聊天室
#服务器端import socket import threading #创建一个TCP端 sock = socket.socket(socket.AF_INET, socket.SOCK_STREA ...
- TCPIP协议编程:基于UDP协议的局域网聊天工具的研发
任务目标 聊天器采用客户端/服务器(C/S)模式: 客户端利用UDP与服务器相连,客户端与客户端之间通过UDP相互通信: 服务器端具有服务器端口设置维护客户端个人信息,记录客户端状态,分配账号等: 客 ...
- 学习WebSocket(二):使用Spring WebSocket做一个简单聊天室
聊天室高频率.低延时完全符合websocket的特点,所以聊天室使用websocket再适合不过了. 聊天室的功能并没有比上一节代码多多少,主要在握手阶段对用户的session做处理,对用户的消息进行 ...
- 关于yum网络版仓库(本地yum仓库的安装配置,如果没网了,做一个局域网内的yum仓库)
2017-11-13 22:49:48 1:两种方式: a.每一台机器都配一个本地文件系统上的yum仓库 file:///packege/path/ b.在局域网内部配置一台节点(server-b ...
- C#局域网聊天工具_UDP广播
接上一讲,程序启动就要发送广播消息,如何发送广播消息,这一讲将给大家好好讲讲网络广播的知识,以及C#如何实现广播. 第一部分.什么是广播地址,以及广播地址怎么计算 1.1 广播地址是什么? 主机号全为 ...
随机推荐
- 解决uploadify多图片上传部分图片丢失,且不提示任何错误的问题
这两天用到uploadify的flash版本进行批量图片上传并生成缩略图的功能,之前用uploadify用的好好的,这次突然出现了一个奇怪的问题. 问题描述如下:当我选择单个图片上传的时候,图片上传都 ...
- hql语句理解2
/* * this.getSession().createQuery("sdfdf").executeUpdate();这里面的query可以是delete,update,inse ...
- 微软TechEd2013大会将在北京、上海召开!
微软TechEd2013大会将在北京.上海召开 大家期盼已久的微软TechEd2013大会终于到来了! 我公司依旧是微软公司指定票商 ,继续为您提供最最优质的售前咨询.最最完善的售后服务! 微软Tec ...
- 图表控件Edraw Max免费下载地址
Edraw Max软件能使学生.老师和商务人士创建并发布各种设计图,它是一个集所有功能于一身的图表控件软件,它可以轻松地创建具有专业外观的流程图.组织结构图.网络图.商业演示图.建筑设计图.思维导图. ...
- php大力力 [028节] 如何下载js文件,网上一个*.js无法下载啊??????
php大力力 [028节] 如何下载js文件,网上一个*.js无法下载啊?????? safari也无法下载 迅雷也无法下载 是不是对方网站服务器的不让下载那个js目录的文件??? 只能调用js函数啊 ...
- 爬虫学习----pattern
1.match match(string[, pos[, endpos]]) | re.match(pattern, string[, flags]): 这个方法将从string的pos下标处起尝试匹 ...
- 产生n位元的所有格雷码
原文链接:http://blog.csdn.net/beiyeqingteng/article/details/7044471 问题:产生n位元的所有格雷码. 格雷码(Gray Code)是一个数列集 ...
- Smart210学习记录-----linux定时器
1.内核定时器: Linux 内核所提供的用于操作定时器的数据结构和函数如下: (1) timer_list 在 Linux 内核中,timer_list 结构体的一个实例对应一个定时器 1 stru ...
- 关于python的一些笔记
Python源文件默认以UTF-8编码.在这种编码下,世界上大多数语言的字符可以在字符串,标识符和注释中同时使用 — 尽管标准库中的标识符只使用ASCII字符,它是可移植代码应该遵循的一个惯例.为了能 ...
- Redis 设计与实现读书笔记一 Redis字符串
1 Redis 是C语言实现的 2 C字符串是 /0 结束的字符数组 3 Redis具体的动态字符串实现 /* * 保存字符串对象的结构 */ struct sdshdr { // buf 中已占用空 ...