第一次做CS的程序,关于socket的,通过各种资料的搜索,其实我觉得说白了主要就分为:
1、套结的关键字。
2、服务器和客户机的远程通信。
3、消息的处理。
服务器原理:
1 //把ip地址转换为实例 2 IPAddress ipa = IPAddress.Parse("127.0.0.1"); 3 //监听端口8001 4 TcpListener mylsn = new TcpListener(ipa, 8001); 5 //开启监听 6 mylsn.Start(); 7 //输出监听成功的信息 8 Console.WriteLine("在8001启动服务,等待连接"); 9 //等待处理接入连接请求 10 while (true) 11 { 12 Socket mysock = mylsn.AcceptSocket(); 13 Console.WriteLine("有连接,连接来自" + mysock.RemoteEndPoint); 14 work w = new work(); 15 w.mysock = mysock; 16 w.mylsn = mylsn; 17 Thread t = new Thread(new ThreadStart(w.main)); 18 t.Start(); 19 }
class类:
1 class work 2 { 3 public Socket mysock; 4 public TcpListener mylsn; 5 public void main() 6 { 7 //接收客户端消息 8 byte[] data = new byte[100]; 9 mysock.Receive(data); 10 string rt = System.Text.UTF8Encoding.UTF8.GetString(data); 11 Console.WriteLine(rt); 12 //给客户端发消息 13 mysock.Send(UTF8Encoding.UTF8.GetBytes("server callback")); 14 //释放资源 15 mysock.Close(); 16 mylsn.Stop(); 17 } 18 }
客户机原理:
1 int port = 8001; 2 string host = "127.0.0.1"; 3 //创建终结点EndPoint 4 IPAddress ip = IPAddress.Parse(host); 5 IPEndPoint ipe = new IPEndPoint(ip, port); //把ip和端口转化为IPEndPoint的实例 6 7 //创建Socket并连接到服务器 8 Socket c = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 创建Socket 9 Console.WriteLine("Connecting..."); 10 c.Connect(ipe); //连接到服务器 11 12 //向服务器发送信息 13 string sendStr = "Hello,this is a socket test"; 14 byte[] bs = Encoding.ASCII.GetBytes(sendStr); //把字符串编码为字节 15 16 Console.WriteLine("Send message"); 17 c.Send(bs, bs.Length, 0); //发送信息 18 19 //接受从服务器返回的信息 20 string recvStr = ""; 21 byte[] recvBytes = new byte[1024]; 22 int bytes; 23 bytes = c.Receive(recvBytes, recvBytes.Length, 0); //从服务器端接受返回信息 24 recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes); 25 Console.WriteLine("client get message:{0}", recvStr); //回显服务器的返回信息 26 27 Console.ReadLine(); 28 //一定记着用完Socket后要关闭 29 c.Close();
命名空间:System.Net和System.Net.Sockets(通信) System.IO(消息字节处理)
到这里,我想通信已经完整的建立了,但是有些小朋友肯定会问,这只是一个简单的客户机和主机的联系,那么,一个主机,N个客户机,又是怎么回事呢,
服务器原理:
1 private TcpListener myListener; 2 myListener = new TcpListener(localAddress, port); 3 myListener.Start(); 4 5 service.AddItem(string.Format("开始在{0}:{1}监听客户端连接", localAddress, port)); 6 //创建一个线程监听客户端连接请求 7 ThreadStart ts = new ThreadStart(ListenClientConnect);//委托 8 Thread myThread = new Thread(ts); 9 myThread.Start(); 10 11 12 private void ListenClientConnect() 13 { 14 while (true) 15 { 16 TcpClient newClient = null; 17 try 18 { 19 //等待用户进入 20 newClient = myListener.AcceptTcpClient(); 21 } 22 catch 23 { 24 //当单击“停止监听”或者退出此窗体时AcceptTcpClient()会产生异常 25 //因此可以利用此异常退出循环 26 break; 27 } 28 //每接受一个客户端连接,就创建一个对应的线程循环接收客户端发来的信息 29 ParameterizedThreadStart pts = new ParameterizedThreadStart(ReceiveData);//委托 30 Thread threadReceive = new Thread(pts); 31 User user = new User(newClient); 32 threadReceive.Start(user); 33 userList.Add(user); 34 service.AddItem(string.Format("{0}进入", newClient.Client.RemoteEndPoint)); 35 service.AddItem(string.Format("当前连接用户数:{0}", userList.Count)); 36 } 37 } 38 39 private void ReceiveData(object obj) 40 { 41 User user = (User)obj; 42 TcpClient client = user.client; 43 //是否正常退出接收线程 44 bool normalExit = false; 45 //用于控制是否退出循环 46 bool exitWhile = false; 47 while (exitWhile == false) 48 { 49 //当前要传送的数据 50 string receiveString = null; 51 try 52 { 53 receiveString = user.sr.ReadLine(); 54 } 55 catch (Exception ex) 56 { 57 //该客户底层套接字不存在时会出现异常 58 service.AddItem("接收数据失败,原因:" + ex.Message); 59 } 60 //TcpClient 对象将套接字进行了封装,如果TcpClient对象关闭了, 61 //但是底层套接字未关闭,并不产生异常,但是读取的结果为 null 62 if (receiveString == null) 63 { 64 if (normalExit == false) 65 { 66 //如果停止了监听,Connected 为 false 67 if (client.Connected == true) 68 { 69 service.AddItem(string.Format("与{0}失去联系,已停止接收该用户信息", 70 client.Client.RemoteEndPoint)); 71 } 72 } 73 //退出循环 74 break; 75 } 76 service.AddItem(string.Format("来自{0}:{1}", user.userName, receiveString)); 77 string[] splitString = receiveString.Split(','); 78 string command = splitString[0].ToLower(); 79 //获取当前传送的数据 80 switch (command) 81 { 82 default: 83 service.SendToAll(userList, "要发送的数据"); 84 break; 85 } 86 } 87 userList.Remove(user); 88 client.Close(); 89 service.AddItem(string.Format("有一个退出,剩余连接用户数:{0}", userList.Count)); 90 }
Service类:
class Service { private ListBox listbox; private delegate void AddItemDelegate(string str); private AddItemDelegate addItemDelegate; public Service(ListBox listbox) { this.listbox = listbox; addItemDelegate = new AddItemDelegate(AddItem); } /// <summary> /// 在listbox中追加信息 /// </summary> /// <param name="str">要追加的信息</param> public void AddItem(string str) { if (listbox.InvokeRequired) listbox.Invoke(addItemDelegate, str); else { listbox.Items.Add(str); listbox.SelectedIndex = listbox.Items.Count - 1; listbox.ClearSelected(); } } /// <summary> /// 向某个客户端发送信息 /// </summary> /// <param name="user">指定客户</param> /// <param name="str">信息</param> public void SendToOne(User user, string str) { try { user.sw.WriteLine(str); user.sw.Flush(); AddItem(string.Format("向{0}发送{1}", user.userName, str)); } catch (Exception ex) { AddItem(string.Format("向{0}发送消息失败,原因:{1}", user.userName, ex.Message)); } } /// <summary> /// 向所有客户端发送信息 /// </summary> /// <param name="userList">客户列表</param> /// <param name="str">信息</param> public void SendToAll(List<User> userList, string str) { for (int i = 0; i < userList.Count; i++) { SendToOne(userList[i], str); } } }
客户机组(list)类:
1 /// <summary> 2 /// 客户机 3 /// </summary> 4 class User 5 { 6 public TcpClient client { get; set; } 7 public StreamReader sr { get; private set; } 8 public StreamWriter sw { get; private set; } 9 public string userName { get; set; } 10 public User(TcpClient client) 11 { 12 this.client = client; 13 this.userName = ""; 14 NetworkStream netStream = client.GetStream(); 15 sr = new StreamReader(netStream, Encoding.UTF8); 16 sw = new StreamWriter(netStream, Encoding.UTF8); 17 } 18 }
其实,现在呢,就是把整个客户机放到一个list里面,而listbox只是为了单纯的显示消息而已
客户机原理:
1 private TcpClient client = null; 2 private StreamWriter sw; 3 private StreamReader sr; 4 private Service service; 5 //是否正常退出接收线程 6 private bool normalExit = false; 7 8 /// <summary> 9 /// 连接服务器 10 /// </summary> 11 private void GetService() 12 { 13 try 14 { 15 client = new TcpClient(); 16 //服务器IP 17 client.Connect(IPAddress.Parse(ConfigurationManager.AppSettings["IP"]), int.Parse(ConfigurationManager.AppSettings["Port"])); 18 //获取网络流 19 NetworkStream netStream = client.GetStream(); 20 sr = new StreamReader(netStream, System.Text.Encoding.UTF8); 21 sw = new StreamWriter(netStream, System.Text.Encoding.UTF8); 22 //信息基本提示 23 service = new Service(listBox1, sw); 24 //给服务器消息 25 service.SendToServer("success"); 26 //数据处理(服务器消息) 27 Thread threadReceive = new Thread(new ThreadStart(ReceiveData)); 28 threadReceive.Start(); 29 } 30 catch (Exception ex) 31 { 32 MessageBox.Show("与服务器连接失败,原因:" + ex.Message, "提示", 33 MessageBoxButtons.OK, MessageBoxIcon.Information); 34 return; 35 } 36 37 } 38 /// <summary> 39 /// 接受服务器端的消息 40 /// </summary> 41 private void ReceiveData() 42 { 43 bool exitWhile = false; 44 while (exitWhile == false) 45 { 46 string receiveString = null; 47 try 48 { 49 receiveString = sr.ReadLine(); 50 } 51 catch 52 { 53 service.AddItemToListBox("接收数据失败"); 54 } 55 if (receiveString == null) 56 { 57 if (normalExit == false) 58 { 59 MessageBox.Show("与服务器失去联系!"); 60 } 61 //结束线程 62 break; 63 } 64 service.AddItemToListBox("收到:" + receiveString); 65 string[] splitString = receiveString.Split(','); 66 string command = splitString[0].ToLower(); 67 switch (command) 68 { 69 default: 70 GetControl(command);//这里的GetControl是一个处理值的方法, 71 this.Invalidate(); 72 break; 73 } 74 } 75 Application.Exit(); 76 }
客户机Service类:
1 class Service 2 { 3 ListBox listbox; 4 StreamWriter sw; 5 public Service(ListBox listbox, StreamWriter sw) 6 { 7 this.listbox = listbox; 8 this.sw = sw; 9 } 10 /// <summary>向服务器发送数据</summary> 11 public void SendToServer(string str) 12 { 13 try 14 { 15 sw.WriteLine(str); 16 sw.Flush(); 17 } 18 catch 19 { 20 AddItemToListBox("发送数据失败"); 21 } 22 } 23 delegate void ListBoxDelegate(string str); 24 /// <summary>在listbox中追加信息<</summary> 25 /// <param name="str">要追加的信息</param> 26 public void AddItemToListBox(string str) 27 { 28 try 29 { 30 if (listbox.InvokeRequired) 31 { 32 ListBoxDelegate d = AddItemToListBox; 33 listbox.Invoke(d, str); 34 } 35 else 36 { 37 listbox.Items.Add(str); 38 listbox.SelectedIndex = listbox.Items.Count - 1; 39 listbox.ClearSelected(); 40 } 41 } 42 catch 43 { 44 45 } 46 } 47 }
这就是一个完整的socket了,第一次做,肯定很多没有想到的地方,希望大神及时提出宝贵意见。