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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace C03聊天室服务端
{
public delegate void DGCloseConn(string endpoint);
}
委托类DGShowMsg
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace C03聊天室服务端
{
public delegate void DGShowMsg(string msg);
}
MsgConnection类
using System;
using System.Collections.Generic;
using System.Text; using System.Net;
using System.Net.Sockets;
using System.Threading; namespace C03聊天室服务端
{
/// <summary>
/// 通信管理类 - 负责 处理 与某个 客户端通信的过程
/// </summary>
public class MsgConnection
{
/// <summary>
/// 与某个 客户端通信的套接字
/// </summary>
Socket sokMsg = null;
/// <summary>
/// 通信线程
/// </summary>
Thread thrMsg = null;
/// <summary>
/// 在窗体显示消息的方法
/// </summary>
DGShowMsg dgShow = null;
/// <summary>
/// 关闭 客户端连接 方法
/// </summary>
DGCloseConn dgCloseConn = null; #region 0.0 构造函数
public MsgConnection(Socket sokMsg, DGShowMsg dgShow, DGCloseConn dgCloseConn)
{
this.sokMsg = sokMsg;
this.dgShow = dgShow;
this.dgCloseConn = dgCloseConn;
//创建通信线程 负责 调用 通信套接字 来接受客户端消息
thrMsg = new Thread(ReceiveMsg);
thrMsg.IsBackground = true;
thrMsg.Start(this.sokMsg);
}
#endregion bool isReceive = true;
#region 2.0 接收客户端消息
void ReceiveMsg(object obj)
{
Socket sokMsg = obj as Socket;
//3.通信套接字 监听 客户端的 消息
//3.1创建 消息缓存区
byte[] arrMsg = new byte[ * * ];
try
{
while (isReceive)
{
//3.2接收客户端的消息 并存入 缓存区,注意:Receive方法也会阻断当前的线程
// 并 返回 真实 接收到客户端 数据的 字节长度
int realLength = sokMsg.Receive(arrMsg);
//3.3将接收到的消息 转成 字符串
string strMsg = System.Text.Encoding.UTF8.GetString(arrMsg, , realLength);
//3.4将消息 显示到 文本框
dgShow(strMsg);
}
}
catch (Exception ex)
{
//调用 窗体类的 关闭移除方法
dgCloseConn(sokMsg.RemoteEndPoint.ToString());
//显示消息
dgShow("客户端断开连接~!");
}
}
#endregion #region 3.0 向客户端发送 文本消息 +void SendMsg(string msg)
/// <summary>
/// 3.0 向客户端发送 文本消息
/// </summary>
/// <param name="msg"></param>
public void SendMsg(string msg)
{
//使用 指定的 通信套接字 将 字符串 发送到 指定的客户端
byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(msg);
try
{
byte[] newArr = MakeNew("str", arrMsg);
sokMsg.Send(newArr);
}
catch (Exception ex)
{
dgShow("异常:" + ex.Message);
}
}
#endregion #region 4.0 向客户端 发送 文本 文件 +void SendFile(string strPath)
/// <summary>
/// 4.0 向客户端 发送 文本 文件
/// </summary>
/// <param name="strFilePath"></param>
public void SendFile(string strFilePath)
{
//6.2 读取要发送的文件
byte[] arrFile = System.IO.File.ReadAllBytes(strFilePath);
byte[] arrNew = MakeNew("file", arrFile);
//6.3 向客户端 发送文件
sokMsg.Send(arrNew);
}
#endregion #region 5.0 向客户端 发送抖屏命令 +void SendShake()
/// <summary>
/// 5.0 向客户端 发送抖屏命令
/// </summary>
public void SendShake()
{
sokMsg.Send(new byte[] { });
}
#endregion #region 5.0 返回带标识的 新数组 +byte[] MakeNew(string type, byte[] oldArr)
/// <summary>
/// 返回带标识的 新数组
/// </summary>
/// <param name="type"></param>
/// <param name="oldArr"></param>
/// <returns></returns>
public byte[] MakeNew(string type, byte[] oldArr)
{
//6.2 创建一个新数组(是原数组长度 + 1)
byte[] newArrFiel = new byte[oldArr.Length + ];
//6.3 将原数组数据 复制到 新数组中(从新数组下标为1的位置放)
oldArr.CopyTo(newArrFiel, );
//6.4 根据 内容类型, 为新数组第一个元素 设置标识符号
switch (type.ToLower())
{
case "str":
newArrFiel[] = ;//只能存 0-255之间的数值, 'a'; // byte = 8 bit , 1bit = 1个 0 或者 1 , 256
break;
case "file":
newArrFiel[] = ;
break;
default:
newArrFiel[] = ;
break;
}
return newArrFiel;
}
#endregion #region 4.0 关闭通信
/// <summary>
/// 关闭通信
/// </summary>
public void Close()
{
isReceive = false;
sokMsg.Close();
sokMsg = null;
}
#endregion
}
}
FormServer
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms; using System.Net.Sockets;
using System.Net;
using System.Threading; namespace C03聊天室服务端
{
public partial class FormServer : Form
{
public FormServer()
{
InitializeComponent();
TextBox.CheckForIllegalCrossThreadCalls = false;
} //服务端 监听套接字
Socket sokWatch = null;
//服务端 监听线程
Thread thrWatch = null;
//字典集合:保存 通信套接字
Dictionary<string, MsgConnection> dictCon = new Dictionary<string, MsgConnection>(); #region 1.0 启动监听
private void btnStartListen_Click(object sender, EventArgs e)
{
try
{
//1.创建【监听套接字】 使用 ip4协议,流式传输,TCP连接
sokWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//2.绑定端口
//2.1获取网络节点对象
IPAddress address = IPAddress.Parse(txtIP.Text);
IPEndPoint endPoint = new IPEndPoint(address, int.Parse(txtPort.Text));
//2.2绑定端口(其实内部 就向系统的 端口表中 注册 了一个端口,并指定了当前程序句柄)
sokWatch.Bind(endPoint);
//2.3设置监听队列(指,限制 同时 处理的 连接请求数--即同时处理的客户端连接请求)
sokWatch.Listen();
//2.4开始监听,调用监听线程 执行 监听套接字的 监听方法
thrWatch = new Thread(WatchConnecting);
thrWatch.IsBackground = true;
thrWatch.Start();
ShowMsg("服务器启动啦~~!");
}
catch (SocketException sex)
{
MessageBox.Show("异常:" + sex);
}
catch (Exception ex)
{
MessageBox.Show("异常:" + ex);
}
}
#endregion bool isWatch = true;
#region 1.0 服务端监听方法 void WatchConnecting()
/// <summary>
/// 服务端监听方法
/// </summary>
void WatchConnecting()
{
try
{
//循环监听 客户端的 连接请求
while (isWatch)
{
//2.4开始监听:此方法会阻断当前线程,直到有 其它程序 连接过来,才执行完毕
Socket sokMsg = sokWatch.Accept();
//2.5创建通信管理类
MsgConnection conn = new MsgConnection(sokMsg, ShowMsg, RemoveClient); //将当前连接成功的 【与客户端通信的套接字】 的 标识 保存起来,并显示到 列表中
//将 远程客户端的 ip和端口 字符串 存入 列表
lbOnline.Items.Add(sokMsg.RemoteEndPoint.ToString());
//将 服务端的通信套接字 存入 字典集合
dictCon.Add(sokMsg.RemoteEndPoint.ToString(), conn); ShowMsg("有客户端连接了~~!");
}
}
catch (Exception ex)
{
ShowMsg("异常:" + ex);
}
}
#endregion #region 3.0 服务端 向指定 的客户端 发送 消息
/// <summary>
/// 3.0 服务端 向指定 的客户端 发送 消息
/// </summary>
private void btnSend_Click(object sender, EventArgs e)
{
string strClient = lbOnline.Text;
if (dictCon.ContainsKey(strClient))
{
string strMsg = txtInput.Text.Trim();
ShowMsg("向客户端【" + strClient + "】说:" + strMsg); //使用 指定的 通信套接字 将 字符串 发送到 指定的客户端
try
{
dictCon[strClient].SendMsg(strMsg);
}
catch (Exception ex)
{
ShowMsg("异常:" + ex.Message);
}
}
}
#endregion #region 4.0 根据 要中断 的客户端 ipport 关闭 连接 +void RemoveClient(string clientIpPort)
/// <summary>
/// 根据 要中断 的客户端 ipport 关闭 连接
/// </summary>
/// <param name="clientIpPort"></param>
public void RemoveClient(string clientIpPort)
{
//1.移除列表中的项
lbOnline.Items.Remove(clientIpPort);
//2.关闭通信管理类
dictCon[clientIpPort].Close();
//3.从字典中 移除 对应的通信管理类 项
dictCon.Remove(clientIpPort);
}
#endregion #region 5.0 选择要发送的文件
/// <summary>
/// 选择要发送的文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnChooseFile_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
//将选中的要发送的文件路径 显示到 文本框 中
txtFilePath.Text = ofd.FileName;
}
}
#endregion #region 6.0 发送文件
/// <summary>
/// 6.0 发送文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSendFile_Click(object sender, EventArgs e)
{
string strClient = lbOnline.Text;
if (dictCon.ContainsKey(strClient))
{
string strMsg = txtInput.Text.Trim();
//使用 指定的 通信套接字 将 字符串 发送到 指定的客户端
try
{
dictCon[strClient].SendFile(txtFilePath.Text.Trim());
}
catch (Exception ex)
{
ShowMsg("异常:" + ex.Message);
}
}
}
#endregion /// <summary>
/// 向指定的客户端发送抖屏命令!
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnShack_Click(object sender, EventArgs e)
{
string strClient = lbOnline.Text;
if (dictCon.ContainsKey(strClient))
{
string strMsg = txtInput.Text.Trim();
//使用 指定的 通信套接字 将 字符串 发送到 指定的客户端
try
{
dictCon[strClient].SendShake();
}
catch (Exception ex)
{
ShowMsg("异常:" + ex.Message);
}
}
} void ShowMsg(string strmsg)
{
this.txtShow.AppendText(strmsg + "\r\n");
} }
}
客户端代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms; using System.Net.Sockets;
using System.Net;
using System.Threading; namespace C04聊天室客户端
{
public partial class FormClient : Form
{
public FormClient()
{
InitializeComponent();
TextBox.CheckForIllegalCrossThreadCalls = false;
}
//客户端 通信套接字
Socket sokMsg = null;
//客户端 通信线程
Thread thrMsg = null; #region 1.0 发送链接服务端请求
private void btnConnect_Click(object sender, EventArgs e)
{
try
{
//1.创建监听套接字 使用 ip4协议,流式传输,TCP连接
sokMsg = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//2.获取要连接的服务端 节点
//2.1获取网络节点对象
IPAddress address = IPAddress.Parse(txtIP.Text);
IPEndPoint endPoint = new IPEndPoint(address, int.Parse(txtPort.Text));
//3.向服务端 发送链接请求
sokMsg.Connect(endPoint);
ShowMsg("连接服务器成功~~!");
//4.开启通信线程
thrMsg = new Thread(RecevieMsg);
thrMsg.IsBackground = true;
thrMsg.SetApartmentState(ApartmentState.STA);//win7 win8 需要设置 客户端通信线程 同步设置,才能在接收文件时 打开 文件选择框
thrMsg.Start();
}
catch (Exception ex)
{
ShowMsg("连接服务器失败:" + ex.Message);
}
}
#endregion bool isRec = true;
#region 2.0 接收服务端消息
void RecevieMsg()
{
//3.1创建 消息缓存区
byte[] arrMsg = new byte[ * * ];
try
{
while (isRec)
{
//此处 接收 服务器发来的数据中,因为包含了一个 标识符,所以内容的真实长度,应该 - 1
int realLength = sokMsg.Receive(arrMsg) - ; switch (arrMsg[])
{
case ://接收到文本消息
GetMsg(arrMsg, realLength);
break;
case ://接收的文件
GetFile(arrMsg, realLength);
break;
default:
ShakeWindow();
break;
}
}
}
catch (Exception ex)
{
sokMsg.Close();
sokMsg = null;
ShowMsg("服务端断开连接!");
}
}
#endregion #region 2.1 接收服务端文本消息并显示 + void GetMsg(byte[] arrContent, int realLength)
/// <summary>
/// 接收服务端文本消息并显示
/// </summary>
/// <param name="arrContent"></param>
/// <param name="realLength"></param>
public void GetMsg(byte[] arrContent, int realLength)
{
//获取 接收的内容(去掉 第一个标识符)
string strMsg = System.Text.Encoding.UTF8.GetString(arrContent, , realLength);
ShowMsg("服务器说:" + strMsg);
}
#endregion #region 2.2 保存文件
/// <summary>
/// 保存文件
/// </summary>
/// <param name="arrContent"></param>
/// <param name="realLength"></param>
public void GetFile(byte[] arrContent, int realLength)
{
SaveFileDialog sfd = new SaveFileDialog();
if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string savePath = sfd.FileName;
//使用文件流 保存文件
using (System.IO.FileStream fs = new System.IO.FileStream(savePath, System.IO.FileMode.OpenOrCreate))
{
//将收到的文件数据数组 从 下标为1的数据开始写入 硬盘,一共写真实数据长度
fs.Write(arrContent, , realLength);
}
ShowMsg("保存文件到【" + savePath + "】成功~!");
}
}
#endregion Random ran = new Random(); #region 2.3 窗体抖动 +void ShakeWindow()
/// <summary>
/// 窗体抖动
/// </summary>
public void ShakeWindow()
{
//1.保存窗体原来位置
Point oldPoint = this.Location;
for (int i = ; i < ; i++)
{
//2.随机生成一个新位置
Point newPoint = new Point(oldPoint.X + ran.Next(), oldPoint.Y + ran.Next());
//3.将新位置 设置给 窗体
this.Location = newPoint;
//4.休息15毫秒
System.Threading.Thread.Sleep();
this.Location = oldPoint;
//4.休息15毫秒
System.Threading.Thread.Sleep();
}
}
#endregion #region 3.0 发送消息
private void btnSend_Click(object sender, EventArgs e)
{
string strMsg = txtInput.Text.Trim();
byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);
try
{
sokMsg.Send(arrMsg);
}
catch (Exception ex)
{
ShowMsg("发送消息失败~!" + ex.Message);
}
}
#endregion void ShowMsg(string strmsg)
{
this.txtShow.AppendText(strmsg + "\r\n");
}
}
}
5、 整个程序模拟场景(为了便于理解)
------------------------------------------------------------------------------------------------------------------------------------------
软谋在线教育,最适合大学生、上班族的在线软件培训,主要教授asp.net动态网站制作,yy教育房间远程实时授课,每节课录制成高清视频课后分享,老师白天八小时全职在线辅导,不懂就问。加qq群:138800420 即可免费试听。
Socket知识总结的更多相关文章
- 运维都该会的Socket知识!
本篇博客转自赵班长 所有运维都会的Socket知识!!! 原创: 赵班长 新运维社区 什么是Socket? 大家都用电脑上网,当我们访问运维社区https://www.unixhot.com的时候,我 ...
- iOS网络HTTP、TCP、UDP、Socket 知识总结
OSI 七层模型 我们一般使用的网络数据传输由下而上共有七层,分别为物理层.数据链路层.网络层.传输层.会话层.表示层.应用层,也被依次称为 OSI 第一层.第二层.⋯⋯. 第七层. 如下图: 各层功 ...
- python的基础socket知识
对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. 代码意思if __name__ == '__main__':是主文件的话就先执行main函数, ...
- 关于socket知识整理
一个完整的计算机系统是由硬件.操作系统.应用软件三者组成,具备了这三个条件,一台计算机系统就可以玩单机游戏.如果你想上网(访问个黄色网站,发个黄色微博啥的),就需要遵守网络协议,即计算机之间交流的标准 ...
- 25 (OC)* iOS网络HTTP、TCP、UDP、Socket 知识总结
应用层:1.用户接口.应用程序:2.Application典型设备:网关:3.典型协议.标准和应用:TELNET.FTP.HTTP 表示层:1.数据表示.压缩和加密presentation2.典型设备 ...
- Windows Socket知识总结
目录 0 理解Socket 1 WinSock API 2 阻塞socket 3 非阻塞Socket 4 套接字IO模型 4.1 套接字IO模型:select(选择) 4.2 套接字IO模型:W ...
- TCP/IP、TCP、UDP、Socket知识汇总
带你了解TCP/IP,UDP,Socket之间关系 https://blog.csdn.net/chaoshenzhaoxichao/article/details/79785318 主要知识点: T ...
- IOS Socket 01-网络协议基础知识
1. 网络参考模型 OSI参考模型 TCP/IP参考模型 2. 七层简述 1)物理层:主要定义物理设备标准,如网线的接 ...
- IOS Socket 05-XMPP开始&安装服务器openfire&安装配置客户端
1. 即时通讯技术简介(IM) 即时通讯技术(IM-Instant Messageing)支持用户在线实时交谈.如果要发送一条信息,用户需要打开一个小窗口,以便让用户及其朋友在其中输入信息并让交谈双方 ...
随机推荐
- JVM 必备指南
简介 Java虚拟机(JVM)是Java应用的运行环境,从一般意义上来讲,JVM是通过规范来定义的一个虚拟的计算机,被设计用来解释执行从Java源码编译而来的字节码.更通俗地说,JVM是指对这个规范的 ...
- dynamic调用时报RuntimeBinderException:“object”未包含“xxx”的定义 错误
情况如下:两个项目项目A命名空间 Test.PA 匿名类型所在 项目B命名空间 Test.PB 在Test.PB 中通过dynamic关键字调用Test.PA中匿名类型时报上述错误 解决办法 在项 ...
- Java之ByteArrayInputStream和ByteArrayOutputStream-操作字节数组的类
ByteArrayInputStream和ByteArrayOutputStream 源:内存中的字节数组 目的:内存中的字节数组 这两个流对象不涉及底层资源的调用,操作的都是内存中的数组,所以不需要 ...
- python 输出字符串如果遇到字典
>>> d = {'a':1} >>> print '%s' % 1,d 1 {'a': 1} >>> print '%s %s' % 1,d T ...
- hdoj 2037 今年暑假不AC
今年暑假不AC Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Sub ...
- unity编辑器的搜索框好特么坑啊,居然不支持*号通配符
上图 t:Scene或者点搜索框旁边的 分类按钮 用*.unity是什么也搜索不出来的
- 别名的应用(New-Alias)
New-Alias -name appcmd -value $env:windir\system32\inetsrv\appcmd.exe 这样就可以在当前PS环境下直接使用appcmd了
- 【转】简明vim练级攻略
本文来自:http://coolshell.cn/articles/5426.html vim的学习曲线相当的大(参看各种文本编辑器的学习曲线),所以,如果你一开始看到的是一大堆VIM的命令分类,你一 ...
- HDU 2013 蟠桃记
蟠桃记 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submis ...
- WdatePicker开始日期不能大于结束日期
<input class="input_calendar inputcss" id="startDate" runat="server" ...