前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >c# UDP/TCP协议简单实现(简单聊天工具)

c# UDP/TCP协议简单实现(简单聊天工具)

作者头像
冰封一夏
发布2019-09-11 15:36:34
1.2K0
发布2019-09-11 15:36:34
举报

长时间没有摸这两个协议,写个代码温习下

下面是界面

【服务器界面】

【登陆界面】

【好友列表界面(我登陆了2个)】

【聊天界面】

下面大致讲解下用到的内容

1、用户登陆于服务器通信用到的tcp协议,服务器接收到用户登陆信息(包括ip,端口,用户名等)后,返回已经登陆的用户列表信息(包括ip,端口,用户名等)给这个用户,同时服务器使用Udp协议向已经登陆的用户发送最新用户列表(包括ip,端口,用户名等)用于更新用户列表

2、用户登陆成功后展示好友列表,并启动udp协议的监听(叫监听似乎不太合适,暂且这么叫吧 形象),用以接收好友发来的消息和服务器返回的好友信息(1中提到的发送用户列表信息)

3、关于聊天有被动接收到消息和主动发送消息

先说主动发送消息吧:双击列表的某个好友打开聊天窗口,然后发送内容,通过udp协议向好友发送信息

被动接收消息:当2中提到的udp监听器接收到消息,则打开聊天窗口,并显示信息

4、用户退出时想服务器发送数据退出,用到的tcp协议,服务器接到到信息,更新在线用户列表并向其他用户发送用户最新列表进行更新(用到udp协议)

口才不行,写的有点乱

下面上代码解释下

先来服务器代码,服务器我使用了控制台程序

代码语言:javascript
复制
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Text;
  4 using System.Net.Sockets;
  5 using System.Threading;
  6 using System.Net;
  7 using System.IO;
  8 
  9 namespace QQServer
 10 {
 11     class Program
 12     {
 13         public static List<string> userlist = new List<string>();
 14         static TcpListener tl;
 15         static NetworkStream ns;
 16         static void Main(string[] args)
 17         {
 18             //声明监听对象
 19 
 20             //声明网络流
 21 
 22             //IPEndPoint ip=new IPEndPoint(
 23             tl = new TcpListener(12345);
 24             tl.Start();
 25             Console.WriteLine("TcpListener Star");
 26             //开启线程
 27             Thread th = new Thread(new ThreadStart(listen));
 28             th.IsBackground = true;
 29             th.Start();
 30             while (true)
 31             {
 32                 string index = Console.ReadLine();
 33                 if (index == "exit")
 34                     break;
 35              
 36             }
 37 
 38         }
 39         private static void listen()
 40         {
 41             Console.WriteLine("TcpListenering...");
 42             while (true)
 43             {
 44                 //获得响应的Socket
 45                 Socket sock = tl.AcceptSocket();
 46                 //通过该Socket实例化网络流           
 47                 ns = new NetworkStream(sock);
 48                 //ClientTcp是添加的类,下面会做说明
 49                 ClientTcp ct = new ClientTcp(ns);
 50                 //ct_MyEvent方法注册ClientTcp类的MyEvent事件
 51                 ct.MyEvent += new MyDelegate(ct_MyEvent);
 52                 //开启线程
 53                 Thread th = new Thread(new ThreadStart(ct.TcpThread));
 54                 th.IsBackground = true;
 55                 th.Start();
 56             }
 57         }
 58 
 59 
 60         static void ct_MyEvent(string temp)
 61         {
 62             if (temp.StartsWith("login:"))
 63             {
 64                 temp = temp.Replace("login:", "");
 65                 Console.WriteLine("UserLogin:" + temp);
 66                 string[] index = temp.Split(';');
 67                 if (!ContainsList(index[0]))
 68                 {
 69                     userlist.Add(temp);
 70                 }
 71                 SendUsersToUser(index[0]);
 72             }
 73             else if (temp.StartsWith("out:"))
 74             {
 75                 temp = temp.Replace("out:", "");
 76                 Console.WriteLine("UserLoginOut:" + temp);
 77                 if (ContainsList(temp))
 78                 {
 79                     RemoveList(temp);
 80                 }
 81                 SendUsersToUser(temp);
 82             }
 83         }
 84 
 85         static void SendUsersToUser(string outuser)
 86         {
 87             string message = GetUserStr();
 88             UdpClient uc;
 89             foreach (string s in userlist)
 90             {
 91                 string[] _userstrindex=s.Split(';');
 92                 if (_userstrindex[0] == outuser)
 93                     continue;
 94                 string _ipsindex = _userstrindex[1];
 95                 string[] _ipindex = _ipsindex.Split(':');
 96                 byte[] b = System.Text.Encoding.UTF8.GetBytes("users" + message);
 97                 //向本机的8888端口发送数据
 98                 uc = new UdpClient();
 99                 uc.Send(b, b.Length, _ipindex[0], int.Parse(_ipindex[1]));
100             }
101         }
102 
103         static string GetUserStr()
104         {
105             StringBuilder sb = new StringBuilder();
106             foreach (string s in userlist)
107             {
108                 if (sb.Length > 0)
109                     sb.Append("#");
110                 sb.Append(s);
111             }
112             return sb.ToString();
113         }
114 
115         static bool ContainsList(string str)
116         {
117             foreach (string s in userlist)
118             {
119                 if (s.Split(';')[0] == str)
120                 {
121                     return true;
122                 }
123             }
124             return false;
125         }
126 
127         static void RemoveList(string str)
128         {
129             for (int i = userlist.Count - 1; i >= 0; i--)
130             {
131                 string s = userlist[i];
132                 if (s.Split(';')[0] == str)
133                 {
134                     userlist.Remove(s);
135                 }
136             }
137         }
138     }
139 
140     public delegate void MyDelegate(string temp);
141     class ClientTcp
142     {
143         //设置网络流局部对象
144         private NetworkStream ns;
145         //声明类型为MyDelegate的事件MyEvent
146         public event MyDelegate MyEvent;
147         //构造函数中接收参数以初始化
148         public ClientTcp(NetworkStream ns)
149         {
150             this.ns = ns;
151         }
152         //服务器端线程所调用的方法
153         public void TcpThread()
154         {
155             //获得相关的封装流
156             StreamReader sr = new StreamReader(ns);
157             string temp = sr.ReadLine();
158             //接收到客户端消息后触发事件将消息回传
159             if (!temp.StartsWith("getuser"))
160             {
161                 MyEvent(temp);
162             }
163             StringBuilder sb = new StringBuilder();
164             foreach (string s in Program.userlist)
165             {
166                 if (sb.Length > 0)
167                     sb.Append("#");
168                 sb.Append(s);
169             }
170             StreamWriter sw = new StreamWriter(ns);
171             //转换为大写后发送消息给客户端
172             sw.WriteLine(sb.ToString());
173             sw.Flush();
174             sw.Close();
175             sr.Close();
176         }
177     }
178 }

需要注意的地方:

tl = new TcpListener(12345);这个地方使用了固定端口12345,所有客户端跟服务器进行通信必须使用这个端口

Thread th = new Thread(new ThreadStart(ct.TcpThread)); th.IsBackground = true; th.Start();

这个地方为什么使用一个线程呢???

当接收到一个信息后需要进行处理,如果同时有好多信息进来的话容易堵塞,所有用线程,并且接收到一个信息马上将信息放到 ClientTcp ct = new ClientTcp(ns);这里,然后慢慢进行处理吧

服务器接收到的消息有多种,怎么区分呢???

有登陆的信息,有退出的信息,有获取列表的信息,我们可以在发送的消息内用一些字段进行标记,例如在头部加上“getuser”等等的

=======================================================

下面是客户端的

登陆

代码语言:javascript
复制
 1 using System;
 2 using System.Collections.Generic;
 3 using System.ComponentModel;
 4 using System.Data;
 5 using System.Drawing;
 6 using System.Text;
 7 using System.Windows.Forms;
 8 using System.Net.Sockets;
 9 using System.IO;
10 using System.Net;
11 
12 namespace QQClient
13 {
14     public partial class Login : Form
15     {
16         private TcpClient tc;
17         //声明网络流
18         private NetworkStream ns;
19         public Login()
20         {
21             InitializeComponent();
22         }
23 
24         private void button1_Click(object sender, EventArgs e)
25         {
26             string username = textBox1.Text;
27             string ipstr = textBox2.Text;
28             string poitstr = textBox3.Text;
29 
30             IPHostEntry ipe = Dns.GetHostEntry(Dns.GetHostName());
31             IPAddress ipa = null;
32             foreach (IPAddress ip in ipe.AddressList)
33             {
34                 if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
35                     continue;
36                 ipa = ip;
37                 break;
38             }
39 
40             StringBuilder sb = new StringBuilder();
41             sb.Append("login:");
42             sb.Append(username + ";");
43             sb.Append(ipa.ToString() + ":");
44             Random r = new Random();
45             int port = r.Next(2000, 65535);            
46             sb.Append(port.ToString());
47 
48             try
49             {
50                 tc = new TcpClient(ipstr, int.Parse(poitstr));
51             }
52             catch
53             {
54                 MessageBox.Show("无法连接到主机");
55             }
56             //实例化网络流对象
57             ns = tc.GetStream();
58             StreamWriter sw = new StreamWriter(ns);
59             StreamReader sr = new StreamReader(ns);
60             //将TextBox1的值传给服务器端
61             sw.WriteLine(sb.ToString());
62             sw.Flush();
63             //接收服务器端回传的字符串
64             string users = sr.ReadLine();
65            
66             sr.Close();
67             sw.Close();
68 
69             Main main=new Main();
70             main.Username=username;
71             main.Users=users;
72             main.Port = port;
73             main.ThisIP = ipa.ToString();
74             main.ServerIP = textBox2.Text;
75             main.ServerPort = textBox3.Text;
76             this.Hide();
77             main.ShowDialog();           
78         }
79 
80         private void button2_Click(object sender, EventArgs e)
81         {
82             Application.Exit();
83         }
84     }
85 }

列表界面

代码语言:javascript
复制
  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Text;
  7 using System.Windows.Forms;
  8 using System.Net.Sockets;
  9 using System.IO;
 10 using System.Threading;
 11 using System.Net;
 12 
 13 namespace QQClient
 14 {
 15     public partial class Main : Form
 16     {
 17         public string Username { get; set; }
 18         public string Users { get; set; }
 19         public int Port { get; set; }
 20         public string ServerIP;
 21         public string ServerPort;
 22         public string ThisIP { get; set; }
 23         public static List<Talking> TalkList = new List<Talking>();
 24         public List<User> userList = new List<User>();
 25         public Main()
 26         {
 27             InitializeComponent();
 28         }
 29 
 30         private void Main_Load(object sender, EventArgs e)
 31         {
 32             //Control.CheckForIllegalCrossThreadCalls = false;
 33             this.Text = Username;
 34             LoadUser();
 35             StartListen();
 36         }
 37 
 38         private void LoadUser()
 39         {
 40             if (string.IsNullOrEmpty(Users))
 41                 return;
 42             this.listView1.Items.Clear();
 43             userList.Clear();
 44             string[] _userindex = Users.Split('#');
 45             foreach (string s in _userindex)
 46             {
 47                 string[] _index = s.Split(';');
 48                 string _username = _index[0];
 49                 //string[] _ipinex = _index[1].Split(':');
 50                 //string ip = _ipinex[0];
 51                 //string port = _ipinex[1];
 52                 if (_username != Username)
 53                 {
 54                     //TreeNode tn = new TreeNode();
 55                     //tn.Text = _username;
 56                     //tn.Tag = _index[1];
 57                     //this.treeView1.Nodes.Add(tn);
 58 
 59                     ListViewItem lvitem = new ListViewItem();
 60 
 61                     lvitem.ImageIndex = 0;
 62                     lvitem.Text = _username;
 63                     lvitem.Tag = _index[1];
 64                     this.listView1.Items.Add(lvitem);
 65                     userList.Add(new User() { UserName = _username, Ips = _index[1] });
 66                 }
 67             }
 68         }
 69                
 70 
 71         private void button2_Click(object sender, EventArgs e)
 72         {
 73             Application.Exit();
 74         }
 75 
 76         private void button1_Click(object sender, EventArgs e)
 77         {
 78             try
 79             {
 80                 TcpClient tc = new TcpClient(ServerIP, int.Parse(ServerPort));
 81                 //实例化网络流对象
 82                 NetworkStream ns = tc.GetStream();
 83                 StreamWriter sw = new StreamWriter(ns);
 84                 StreamReader sr = new StreamReader(ns);
 85                 //将TextBox1的值传给服务器端
 86                 sw.WriteLine("getuser");
 87                 sw.Flush();
 88                 //接收服务器端回传的字符串
 89                 Users = sr.ReadLine();
 90                 sr.Close();
 91                 sw.Close();
 92                 LoadUser();
 93             }
 94             catch
 95             { }
 96         }
 97 
 98         private void Main_FormClosed(object sender, FormClosedEventArgs e)
 99         {
100             try
101             {
102                 TcpClient tc = new TcpClient(ServerIP, int.Parse(ServerPort));
103                 //实例化网络流对象
104                 NetworkStream ns = tc.GetStream();
105                 StreamWriter sw = new StreamWriter(ns);
106                 //将TextBox1的值传给服务器端
107                 sw.WriteLine("out:" + Username);
108                 sw.Flush();
109                 sw.Close();
110                 iswork = false;
111             }
112             catch
113             { }
114             Application.Exit();
115         }
116 
117         private void listView1_MouseDoubleClick(object sender, MouseEventArgs e)
118         {
119             if (this.listView1.SelectedItems.Count > 0)
120             {
121                 ListViewItem lvitem = this.listView1.SelectedItems[0];
122                 string toname = lvitem.Text;
123                 string toips = lvitem.Tag.ToString();
124                 Talking t = isHaveTalk(toname);
125                 if (t != null)
126                 {
127                     t.Focus();
128                 }
129                 else
130                 {
131                     Talking talk = new Talking();
132                     talk.UserName = Username;
133                     talk.ToName = toname;
134                     talk.ToIP = toips;
135                     TalkList.Add(talk);
136                     talk.Show();
137                 }
138             }
139         }
140 
141         private Talking isHaveTalk(string toname)
142         {
143             foreach (Talking tk in TalkList)
144             {
145                 if (tk.ToName == toname)
146                     return tk;
147             }
148             return null;
149         }
150 
151         public static void RemoveTalking(Talking _talk)
152         {
153             foreach (Talking tk in TalkList)
154             {
155                 if (tk.ToName == _talk.ToName)
156                 {
157                     TalkList.Remove(_talk);
158                     return;
159                 }
160             }
161         }
162 
163         bool iswork = false;
164         UdpClient uc = null;
165         private void StartListen()
166         {
167 
168             iswork = true;
169             Thread th = new Thread(new ThreadStart(listen));
170             //设置为后台
171             th.IsBackground = true;
172             th.Start();
173         }
174         private void listen()
175         {
176             uc = new UdpClient(Port);
177             IPEndPoint iep = new IPEndPoint(IPAddress.Any, 0);
178             while (iswork)
179             {
180                 //获得Form1发送过来的数据包
181                 string text = System.Text.Encoding.UTF8.GetString(uc.Receive(ref iep));
182                 if (text.StartsWith("message"))
183                 {
184                     text = text.Substring(7);
185                     int indexof = text.IndexOf("#");
186                     string fromuser = text.Substring(0, indexof);
187                     string message = text.Substring(indexof + 1);
188                     Talking _tk = isHaveTalk(fromuser);
189                     if (_tk != null)
190                     {
191                         this.BeginInvoke(new MethodInvoker(delegate()
192                         {
193                             _tk.Focus();
194                             _tk.AddMessage(message, true);
195                         }));
196                     }
197                     else
198                     {
199                         //Talking talk = new Talking(message);
200                         //talk.UserName = Username;
201                         //talk.ToName = fromuser;
202                         //talk.ToIP = GetIP(fromuser);
203                         //TalkList.Add(talk);
204                         //talk.Show();
205                         this.BeginInvoke(new MethodInvoker(delegate()
206                         {
207                             this.CreatTalking(text);
208                         }));
209                         //Thread th = new Thread(new ParameterizedThreadStart(CreatTalking));
210                         //th.IsBackground = true;
211                         //th.Start(text);
212                     }
213                     //加入ListBox
214                     //this.listBox1.Items.Add(text);
215                 }
216                 else if (text.StartsWith("users"))
217                 {
218                     text = text.Substring(5);
219                     Users = text;
220                     LoadUser();
221                 }
222             }
223         }
224 
225         public void CreatTalking(object _text)
226         {
227             string text = _text.ToString();
228             int indexof = text.IndexOf("#");
229             string fromuser = text.Substring(0, indexof);
230             string message = text.Substring(indexof + 1);
231             Talking talk = new Talking(message);
232             talk.UserName = Username;
233             talk.ToName = fromuser;
234             talk.ToIP = GetIP(fromuser);
235             TalkList.Add(talk);
236             talk.Show();
237         }
238 
239         private string GetIP(string toname)
240         {
241             foreach (User user in userList)
242             {
243                 if (user.UserName == toname)
244                     return user.Ips;
245             }
246             return "";
247         }
248     }
249     public class User
250     {
251         private string userName;
252 
253         public string UserName
254         {
255             get { return userName; }
256             set { userName = value; }
257         }
258         private string ips;
259 
260         public string Ips
261         {
262             get { return ips; }
263             set { ips = value; }
264         }
265     }
266 }

聊天界面

代码语言:javascript
复制
  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Text;
  7 using System.Windows.Forms;
  8 using System.Net.Sockets;
  9 using System.Threading;
 10 
 11 namespace QQClient
 12 {
 13     public partial class Talking : Form
 14     {
 15         public string UserName { get; set; }
 16         public string ToName { get; set; }
 17         public string ToIP { get; set; }
 18 
 19         UdpClient uc;
 20         public Talking()
 21         {
 22             InitializeComponent();
 23         }
 24 
 25         string getmessage = string.Empty;
 26         public Talking(string message)
 27         {
 28             getmessage = message;
 29             InitializeComponent();
 30         }
 31 
 32         private void Talking_Load(object sender, EventArgs e)
 33         {
 34             uc = new UdpClient();
 35             this.Text = "和" + ToName + "聊天中";
 36             if (!string.IsNullOrEmpty(getmessage))
 37             {
 38                 ShowTalking();
 39                 AddMessage(getmessage, true);
 40             }
 41         }
 42 
 43         private void button1_Click(object sender, EventArgs e)
 44         {
 45             string temp = this.textBox1.Text; //保存TextBox文本
 46             //将该文本转化为字节数组
 47             byte[] b = System.Text.Encoding.UTF8.GetBytes("message" + UserName + "#" + temp);
 48             //向本机的8888端口发送数据
 49             string[] _ip = ToIP.Split(':');
 50             uc.Send(b, b.Length, _ip[0], int.Parse(_ip[1]));
 51             AddMessage(temp, false);
 52             this.textBox1.Clear();
 53         }
 54         public void AddMessage(string str, bool isuser)
 55         {
 56             int startindex = this.richTextBox1.Text.Length;
 57 
 58             string message = string.Empty;
 59 
 60             if (isuser)
 61                 message = "【" + ToName + "】  " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\n" + str + "\n";
 62             else
 63                 message = "【" + UserName + "】  " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\n" + str + "\n";
 64             this.richTextBox1.AppendText(message);
 65             this.richTextBox1.Select(startindex, message.Length);
 66             if (isuser)
 67             {
 68                 this.richTextBox1.SelectionAlignment = HorizontalAlignment.Left;
 69             }
 70             else
 71             {
 72                 this.richTextBox1.SelectionAlignment = HorizontalAlignment.Right;
 73             }
 74             this.richTextBox1.Select(this.richTextBox1.Text.Length, 0);
 75         }
 76 
 77         [System.Runtime.InteropServices.DllImport("user32")]
 78         private static extern long FlashWindow(IntPtr hwnd, bool bInvert);
 79 
 80         private static void FlashWindow(object _handle)
 81         {
 82             IntPtr handle = (IntPtr)_handle;
 83             int flashindex = 0;
 84             while (true)
 85             {
 86                 if (flashindex > 5)
 87                     break;
 88                 FlashWindow(handle, true);
 89                 flashindex++;
 90                 Thread.Sleep(500);
 91             }
 92         }
 93 
 94         public void ShowTalking()
 95         {
 96             Thread _thread = new Thread(FlashWindow);
 97             _thread.IsBackground = true;
 98             _thread.Start(this.Handle);
 99         }
100 
101         private void Talking_FormClosed(object sender, FormClosedEventArgs e)
102         {
103             Main.RemoveTalking(this);
104         }
105 
106         private void button2_Click(object sender, EventArgs e)
107         {
108             this.Close();
109         }
110     }
111 }

大致总结下:

tcp必须建立连接才可以进行通信

udp不需要建立通信

但是两者都需要一个监听来接收消息

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2014-10-16 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档