一、网络编程相关概念
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
class="code_img_closed" src="/Upload/Images/2014040113/0015B68B3C38AA5B.gif" alt="" />logs_code_hide('f040daf9-5a50-4d9d-ac75-a350cc4b0936',event)" src="/Upload/Images/2014040113/2B1B950FA3DF188F.gif" alt="" />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 即可免费试听。