Socket知识总结

一、网络编程相关概念

1、 互联网通过ip定位电脑

2、 在电脑中通过port定位程序

3、 程序和程序之间通过协议定义通信数据格式

 

二、Socket相关概念

1、 ip地址

1) 每台联网的电脑都有一个唯一的ip地址。

2) 长度32位,分为4段,每段8位,用十进制表示,每段范围0~255.

3) 特殊ip:127.0.0.1用户本地网卡测试。

2、 端口

1) 网络中有很多电脑,这些电脑一般运行了多个网络程序,每种网络程序都打开一个Socket,并绑定到一个端口上,不同的端口对应不同的网络程序。

2) 常用端口,21 ftp, 25 smtp,110 pop3,80 http,443 https

3、 Socket通俗理解:人和人通过电话来通讯,电话号码就相当于是ip地址,人就是程序,套接字就是程序间的电话,程序和程序之间通讯,需要定义通讯协议,就像两个人打电话要先定义好彼此说的语言,这样才能正常通讯。

4、 Socket流式(服务端和客户端)

 

1) 服务器welcoming socket开始监听端口(负责监听客户端的连接信息)

2) 客户端client socket连接服务端制定端口(负责接收和发送服务端信息)

3) 服务端welcoming socket监听到客户端连接,创建connection socket(负责和客户端通讯)

Demo1

服务端代码:

委托类DGCloseConn

1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 
6 namespace C03聊天室服务端
7 {
8     public delegate void DGCloseConn(string endpoint);
9 }
View Code

委托类DGShowMsg

1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 
6 namespace C03聊天室服务端
7 {
8     public delegate void DGShowMsg(string msg);
9 }
View Code

MsgConnection类

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Text;
  4 
  5 using System.Net;
  6 using System.Net.Sockets;
  7 using System.Threading;
  8 
  9 namespace C03聊天室服务端
 10 {
 11     /// <summary>
 12     /// 通信管理类 - 负责 处理 与某个 客户端通信的过程
 13     /// </summary>
 14     public class MsgConnection
 15     {
 16         /// <summary>
 17         /// 与某个 客户端通信的套接字
 18         /// </summary>
 19         Socket sokMsg = null;
 20         /// <summary>
 21         /// 通信线程
 22         /// </summary>
 23         Thread thrMsg = null;
 24         /// <summary>
 25         /// 在窗体显示消息的方法
 26         /// </summary>
 27         DGShowMsg dgShow = null;
 28         /// <summary>
 29         /// 关闭 客户端连接 方法
 30         /// </summary>
 31         DGCloseConn dgCloseConn = null;
 32 
 33         #region 0.0 构造函数
 34         public MsgConnection(Socket sokMsg, DGShowMsg dgShow, DGCloseConn dgCloseConn)
 35         {
 36             this.sokMsg = sokMsg;
 37             this.dgShow = dgShow;
 38             this.dgCloseConn = dgCloseConn;
 39             //创建通信线程 负责 调用 通信套接字 来接受客户端消息
 40             thrMsg = new Thread(ReceiveMsg);
 41             thrMsg.IsBackground = true;
 42             thrMsg.Start(this.sokMsg);
 43         } 
 44         #endregion
 45 
 46         bool isReceive = true;
 47         #region 2.0 接收客户端消息
 48         void ReceiveMsg(object obj)
 49         {
 50             Socket sokMsg = obj as Socket;
 51             //3.通信套接字 监听 客户端的 消息
 52             //3.1创建 消息缓存区
 53             byte[] arrMsg = new byte[1024 * 1024 * 1];
 54             try
 55             {
 56                 while (isReceive)
 57                 {
 58                     //3.2接收客户端的消息 并存入 缓存区,注意:Receive方法也会阻断当前的线程
 59                     //   并 返回 真实 接收到客户端 数据的 字节长度
 60                     int realLength = sokMsg.Receive(arrMsg);
 61                     //3.3将接收到的消息 转成 字符串
 62                     string strMsg = System.Text.Encoding.UTF8.GetString(arrMsg, 0, realLength);
 63                     //3.4将消息 显示到 文本框
 64                     dgShow(strMsg);
 65                 }
 66             }
 67             catch (Exception ex)
 68             {
 69                 //调用 窗体类的 关闭移除方法
 70                 dgCloseConn(sokMsg.RemoteEndPoint.ToString());
 71                 //显示消息
 72                 dgShow("客户端断开连接~!");
 73             }
 74         }
 75         #endregion
 76 
 77         #region 3.0 向客户端发送 文本消息 +void SendMsg(string msg)
 78         /// <summary>
 79         /// 3.0 向客户端发送 文本消息
 80         /// </summary>
 81         /// <param name="msg"></param>
 82         public void SendMsg(string msg)
 83         {
 84             //使用 指定的 通信套接字 将 字符串 发送到 指定的客户端
 85             byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(msg);
 86             try
 87             {
 88                 byte[] newArr = MakeNew("str", arrMsg);
 89                 sokMsg.Send(newArr);
 90             }
 91             catch (Exception ex)
 92             {
 93                 dgShow("异常:" + ex.Message);
 94             }
 95         }
 96         #endregion
 97 
 98         #region 4.0 向客户端 发送 文本 文件 +void SendFile(string strPath)
 99         /// <summary>
100         /// 4.0 向客户端 发送 文本 文件
101         /// </summary>
102         /// <param name="strFilePath"></param>
103         public void SendFile(string strFilePath)
104         {
105             //6.2 读取要发送的文件
106             byte[] arrFile = System.IO.File.ReadAllBytes(strFilePath);
107             byte[] arrNew = MakeNew("file", arrFile);
108             //6.3 向客户端 发送文件
109             sokMsg.Send(arrNew);
110         } 
111         #endregion
112 
113         #region 5.0 向客户端 发送抖屏命令 +void SendShake()
114         /// <summary>
115         /// 5.0 向客户端 发送抖屏命令
116         /// </summary>
117         public void SendShake()
118         {
119             sokMsg.Send(new byte[1] { 2 });
120         } 
121         #endregion
122 
123         #region 5.0 返回带标识的 新数组 +byte[] MakeNew(string type, byte[] oldArr)
124         /// <summary>
125         /// 返回带标识的 新数组
126         /// </summary>
127         /// <param name="type"></param>
128         /// <param name="oldArr"></param>
129         /// <returns></returns>
130         public byte[] MakeNew(string type, byte[] oldArr)
131         {
132             //6.2 创建一个新数组(是原数组长度 + 1)
133             byte[] newArrFiel = new byte[oldArr.Length + 1];
134             //6.3 将原数组数据 复制到 新数组中(从新数组下标为1的位置放)
135             oldArr.CopyTo(newArrFiel, 1);
136             //6.4 根据 内容类型, 为新数组第一个元素 设置标识符号
137             switch (type.ToLower())
138             {
139                 case "str":
140                     newArrFiel[0] = 0;//只能存 0-255之间的数值, 'a'; //  byte = 8 bit   ,  1bit = 1个 0 或者 1 , 256 
141                     break;
142                 case "file":
143                     newArrFiel[0] = 1;
144                     break;
145                 default:
146                     newArrFiel[0] = 2;
147                     break;
148             }
149             return newArrFiel;
150         } 
151         #endregion
152 
153         #region 4.0 关闭通信
154         /// <summary>
155         /// 关闭通信
156         /// </summary>
157         public void Close()
158         {
159             isReceive = false;
160             sokMsg.Close();
161             sokMsg = null;
162         } 
163         #endregion
164     }
165 }
View Code

FormServer

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Linq;
  7 using System.Text;
  8 using System.Windows.Forms;
  9 
 10 using System.Net.Sockets;
 11 using System.Net;
 12 using System.Threading;
 13 
 14 namespace C03聊天室服务端
 15 {
 16     public partial class FormServer : Form
 17     {
 18         public FormServer()
 19         {
 20             InitializeComponent();
 21             TextBox.CheckForIllegalCrossThreadCalls = false;
 22         }
 23 
 24         //服务端 监听套接字
 25         Socket sokWatch = null;
 26         //服务端 监听线程
 27         Thread thrWatch = null;
 28         //字典集合:保存 通信套接字
 29         Dictionary<string, MsgConnection> dictCon = new Dictionary<string, MsgConnection>();
 30 
 31         #region 1.0 启动监听
 32         private void btnStartListen_Click(object sender, EventArgs e)
 33         {
 34             try
 35             {
 36                 //1.创建【监听套接字】 使用 ip4协议,流式传输,TCP连接
 37                 sokWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 38                 //2.绑定端口
 39                 //2.1获取网络节点对象
 40                 IPAddress address = IPAddress.Parse(txtIP.Text);
 41                 IPEndPoint endPoint = new IPEndPoint(address, int.Parse(txtPort.Text));
 42                 //2.2绑定端口(其实内部 就向系统的 端口表中 注册 了一个端口,并指定了当前程序句柄)
 43                 sokWatch.Bind(endPoint);
 44                 //2.3设置监听队列(指,限制 同时 处理的 连接请求数--即同时处理的客户端连接请求)
 45                 sokWatch.Listen(10);
 46                 //2.4开始监听,调用监听线程 执行 监听套接字的 监听方法
 47                 thrWatch = new Thread(WatchConnecting);
 48                 thrWatch.IsBackground = true;
 49                 thrWatch.Start();
 50                 ShowMsg("服务器启动啦~~!");
 51             }
 52             catch (SocketException sex)
 53             {
 54                 MessageBox.Show("异常:" + sex);
 55             }
 56             catch (Exception ex)
 57             {
 58                 MessageBox.Show("异常:" + ex);
 59             }
 60         } 
 61         #endregion
 62 
 63         bool isWatch = true;
 64         #region 1.0 服务端监听方法 void WatchConnecting()
 65         /// <summary>
 66         /// 服务端监听方法
 67         /// </summary>
 68         void WatchConnecting()
 69         {
 70             try
 71             {
 72                 //循环监听 客户端的 连接请求
 73                 while (isWatch)
 74                 {
 75                     //2.4开始监听:此方法会阻断当前线程,直到有 其它程序 连接过来,才执行完毕
 76                     Socket sokMsg = sokWatch.Accept();
 77                     //2.5创建通信管理类
 78                     MsgConnection conn = new MsgConnection(sokMsg, ShowMsg, RemoveClient);
 79 
 80                     //将当前连接成功的 【与客户端通信的套接字】 的 标识 保存起来,并显示到 列表中
 81                     //将 远程客户端的 ip和端口 字符串 存入 列表
 82                     lbOnline.Items.Add(sokMsg.RemoteEndPoint.ToString());
 83                     //将 服务端的通信套接字 存入 字典集合
 84                     dictCon.Add(sokMsg.RemoteEndPoint.ToString(), conn);
 85 
 86                     ShowMsg("有客户端连接了~~!");
 87                 }
 88             }
 89             catch (Exception ex)
 90             {
 91                 ShowMsg("异常:" + ex);
 92             }
 93         } 
 94         #endregion
 95 
 96         #region 3.0 服务端 向指定 的客户端 发送 消息
 97         /// <summary>
 98         /// 3.0 服务端 向指定 的客户端 发送 消息
 99         /// </summary>
100         private void btnSend_Click(object sender, EventArgs e)
101         {
102             string strClient = lbOnline.Text;
103             if (dictCon.ContainsKey(strClient))
104             {
105                 string strMsg = txtInput.Text.Trim();
106                 ShowMsg("向客户端【" + strClient + "】说:" + strMsg);
107 
108                 //使用 指定的 通信套接字 将 字符串 发送到 指定的客户端
109                 try
110                 {
111                     dictCon[strClient].SendMsg(strMsg);
112                 }
113                 catch (Exception ex)
114                 {
115                     ShowMsg("异常:" + ex.Message);
116                 }
117             }
118         } 
119         #endregion
120 
121         #region 4.0 根据 要中断 的客户端 ipport 关闭 连接 +void RemoveClient(string clientIpPort)
122         /// <summary>
123         /// 根据 要中断 的客户端 ipport 关闭 连接
124         /// </summary>
125         /// <param name="clientIpPort"></param>
126         public void RemoveClient(string clientIpPort)
127         {
128             //1.移除列表中的项
129             lbOnline.Items.Remove(clientIpPort);
130             //2.关闭通信管理类
131             dictCon[clientIpPort].Close();
132             //3.从字典中 移除 对应的通信管理类 项
133             dictCon.Remove(clientIpPort);
134         } 
135         #endregion
136 
137         #region 5.0 选择要发送的文件
138         /// <summary>
139         /// 选择要发送的文件
140         /// </summary>
141         /// <param name="sender"></param>
142         /// <param name="e"></param>
143         private void btnChooseFile_Click(object sender, EventArgs e)
144         {
145             OpenFileDialog ofd = new OpenFileDialog();
146             if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
147             {
148                 //将选中的要发送的文件路径 显示到 文本框 中
149                 txtFilePath.Text = ofd.FileName;
150             }
151         } 
152         #endregion
153 
154         #region 6.0 发送文件
155         /// <summary>
156         /// 6.0 发送文件
157         /// </summary>
158         /// <param name="sender"></param>
159         /// <param name="e"></param>
160         private void btnSendFile_Click(object sender, EventArgs e)
161         {
162             string strClient = lbOnline.Text;
163             if (dictCon.ContainsKey(strClient))
164             {
165                 string strMsg = txtInput.Text.Trim();
166                 //使用 指定的 通信套接字 将 字符串 发送到 指定的客户端
167                 try
168                 {
169                     dictCon[strClient].SendFile(txtFilePath.Text.Trim());
170                 }
171                 catch (Exception ex)
172                 {
173                     ShowMsg("异常:" + ex.Message);
174                 }
175             }
176         }
177         #endregion
178 
179         /// <summary>
180         /// 向指定的客户端发送抖屏命令!
181         /// </summary>
182         /// <param name="sender"></param>
183         /// <param name="e"></param>
184         private void btnShack_Click(object sender, EventArgs e)
185         {
186             string strClient = lbOnline.Text;
187             if (dictCon.ContainsKey(strClient))
188             {
189                 string strMsg = txtInput.Text.Trim();
190                 //使用 指定的 通信套接字 将 字符串 发送到 指定的客户端
191                 try
192                 {
193                     dictCon[strClient].SendShake();
194                 }
195                 catch (Exception ex)
196                 {
197                     ShowMsg("异常:" + ex.Message);
198                 }
199             }
200         }
201 
202         void ShowMsg(string strmsg)
203         {
204             this.txtShow.AppendText(strmsg + "\r\n");
205         }
206 
207     }
208 }
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.Linq;
  7 using System.Text;
  8 using System.Windows.Forms;
  9 
 10 using System.Net.Sockets;
 11 using System.Net;
 12 using System.Threading;
 13 
 14 namespace C04聊天室客户端
 15 {
 16     public partial class FormClient : Form
 17     {
 18         public FormClient()
 19         {
 20             InitializeComponent();
 21             TextBox.CheckForIllegalCrossThreadCalls = false;
 22         }
 23         //客户端 通信套接字
 24         Socket sokMsg = null;
 25         //客户端 通信线程
 26         Thread thrMsg = null;
 27 
 28 
 29         #region 1.0 发送链接服务端请求
 30         private void btnConnect_Click(object sender, EventArgs e)
 31         {
 32             try
 33             {
 34                 //1.创建监听套接字 使用 ip4协议,流式传输,TCP连接
 35                 sokMsg = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 36                 //2.获取要连接的服务端 节点
 37                 //2.1获取网络节点对象
 38                 IPAddress address = IPAddress.Parse(txtIP.Text);
 39                 IPEndPoint endPoint = new IPEndPoint(address, int.Parse(txtPort.Text));
 40                 //3.向服务端 发送链接请求
 41                 sokMsg.Connect(endPoint);
 42                 ShowMsg("连接服务器成功~~!");
 43                 //4.开启通信线程
 44                 thrMsg = new Thread(RecevieMsg);
 45                 thrMsg.IsBackground = true;
 46                 thrMsg.SetApartmentState(ApartmentState.STA);//win7 win8 需要设置 客户端通信线程 同步设置,才能在接收文件时 打开 文件选择框
 47                 thrMsg.Start();
 48             }
 49             catch (Exception ex)
 50             {
 51                 ShowMsg("连接服务器失败:" + ex.Message);
 52             }
 53         } 
 54         #endregion
 55 
 56         bool isRec = true;
 57         #region 2.0 接收服务端消息
 58         void RecevieMsg()
 59         {
 60             //3.1创建 消息缓存区
 61             byte[] arrMsg = new byte[1024 * 1024 * 1];
 62             try
 63             {
 64                 while (isRec)
 65                 {
 66                     //此处 接收 服务器发来的数据中,因为包含了一个 标识符,所以内容的真实长度,应该 - 1
 67                     int realLength = sokMsg.Receive(arrMsg) - 1;
 68 
 69                     switch (arrMsg[0])
 70                     {
 71                         case 0://接收到文本消息
 72                             GetMsg(arrMsg, realLength);
 73                             break;
 74                         case 1://接收的文件
 75                             GetFile(arrMsg, realLength);
 76                             break;
 77                         default:
 78                             ShakeWindow();
 79                             break;
 80                     }
 81                 }
 82             }
 83             catch (Exception ex)
 84             {
 85                 sokMsg.Close();
 86                 sokMsg = null;
 87                 ShowMsg("服务端断开连接!");
 88             }
 89         }
 90         #endregion
 91 
 92         #region 2.1 接收服务端文本消息并显示 + void GetMsg(byte[] arrContent, int realLength)
 93         /// <summary>
 94         /// 接收服务端文本消息并显示
 95         /// </summary>
 96         /// <param name="arrContent"></param>
 97         /// <param name="realLength"></param>
 98         public void GetMsg(byte[] arrContent, int realLength)
 99         {
100             //获取 接收的内容(去掉 第一个标识符)
101             string strMsg = System.Text.Encoding.UTF8.GetString(arrContent, 1, realLength);
102             ShowMsg("服务器说:" + strMsg);
103         } 
104         #endregion
105 
106         #region 2.2 保存文件
107         /// <summary>
108         /// 保存文件
109         /// </summary>
110         /// <param name="arrContent"></param>
111         /// <param name="realLength"></param>
112         public void GetFile(byte[] arrContent, int realLength)
113         {
114             SaveFileDialog sfd = new SaveFileDialog();
115             if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
116             {
117                 string savePath = sfd.FileName;
118                 //使用文件流 保存文件
119                 using (System.IO.FileStream fs = new System.IO.FileStream(savePath, System.IO.FileMode.OpenOrCreate))
120                 {
121                     //将收到的文件数据数组 从 下标为1的数据开始写入 硬盘,一共写真实数据长度
122                     fs.Write(arrContent, 1, realLength);
123                 }
124                 ShowMsg("保存文件到【" + savePath + "】成功~!");
125             }
126         } 
127         #endregion
128 
129         Random ran = new Random();
130 
131         #region 2.3 窗体抖动 +void ShakeWindow()
132         /// <summary>
133         /// 窗体抖动
134         /// </summary>
135         public void ShakeWindow()
136         {
137             //1.保存窗体原来位置
138             Point oldPoint = this.Location;
139             for (int i = 0; i < 15; i++)
140             {
141                 //2.随机生成一个新位置
142                 Point newPoint = new Point(oldPoint.X + ran.Next(18), oldPoint.Y + ran.Next(18));
143                 //3.将新位置 设置给 窗体
144                 this.Location = newPoint;
145                 //4.休息15毫秒
146                 System.Threading.Thread.Sleep(25);
147                 this.Location = oldPoint;
148                 //4.休息15毫秒
149                 System.Threading.Thread.Sleep(25);
150             }
151         } 
152         #endregion
153 
154         #region 3.0 发送消息
155         private void btnSend_Click(object sender, EventArgs e)
156         {
157             string strMsg = txtInput.Text.Trim();
158             byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);
159             try
160             {
161                 sokMsg.Send(arrMsg);
162             }
163             catch (Exception ex)
164             {
165                 ShowMsg("发送消息失败~!" + ex.Message);
166             }
167         } 
168         #endregion
169 
170 
171         void ShowMsg(string strmsg)
172         {
173             this.txtShow.AppendText(strmsg + "\r\n");
174         }
175     }
176 }
View Code

5、 整个程序模拟场景(为了便于理解)

------------------------------------------------------------------------------------------------------------------------------------------

 软谋在线教育,最适合大学生、上班族的在线软件培训,主要教授asp.net动态网站制作,yy教育房间远程实时授课,每节课录制成高清视频课后分享,老师白天八小时全职在线辅导,不懂就问。加qq群:138800420 即可免费试听。

posted @ 2014-03-31 10:53  蜡笔小新111  阅读(753)  评论(0编辑  收藏  举报