zoukankan      html  css  js  c++  java
  • c# UDP/TCP协议简单实现(简单聊天工具)

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

    下面是界面

    【服务器界面】

    【登陆界面】

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

    【聊天界面】

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

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

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

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

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

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

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

    口才不行,写的有点乱

    下面上代码解释下

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

      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 }
    View Code

    需要注意的地方:

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

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

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

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

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

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

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

    下面是客户端的

    登陆

     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 }
    View Code

    列表界面

      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 }
    View Code

    聊天界面

      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") + "
    " + str + "
    ";
     62             else
     63                 message = "" + UserName + "" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "
    " + str + "
    ";
     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 }
    View Code

    大致总结下:

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

    udp不需要建立通信

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

  • 相关阅读:
    c++ namespace简单用法
    python2编码问题
    python dict()函数 /// logging模块///yield//生成器和迭代器
    python 对于一个字典,根据其value值获取其对应的keys值
    python 包/库/模块
    python __init()__
    python continue 和 break的区别
    python list去重
    linux命令,将一个文件夹中的内容copy到另外一个文件夹
    python 正则(re.compile()/re.findall())
  • 原文地址:https://www.cnblogs.com/bfyx/p/4028249.html
Copyright © 2011-2022 走看看