Socket通信简介

  第一次做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                 }
View Code

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

  客户机原理:

 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();
View Code

  命名空间: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         }
View Code

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

  客户机组(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     }
View Code

  其实,现在呢,就是把整个客户机放到一个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         }
View Code

  客户机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     }
View Code

  这就是一个完整的socket了,第一次做,肯定很多没有想到的地方,希望大神及时提出宝贵意见。

原文地址:https://www.cnblogs.com/JeffController/p/4398495.html