标签:des style blog http color io os 使用 ar
长时间没有摸这两个协议,写个代码温习下
下面是界面
【服务器界面】
【登陆界面】
【好友列表界面(我登陆了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 }
需要注意的地方:
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 }
列表界面
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 }
聊天界面
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不需要建立通信
但是两者都需要一个监听来接收消息
标签:des style blog http color io os 使用 ar
原文地址:http://www.cnblogs.com/bfyx/p/4028249.html