一、网络编程相关概念

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 即可免费试听。

最新文章

  1. jvm 配置
  2. java中的注解
  3. yum install 安装时报yum doesn&#39;t have enough cached data to continue.
  4. Kali安装
  5. mysql 索引过长1071-max key length is 767 byte
  6. Apache OFBiz 学习笔记 之 服务引擎 二
  7. Android 读取txt文件并以utf-8格式转换成字符串
  8. struts 2学习笔记—初学struts 2
  9. Java基础知识强化20:面向对象和面向过程的思想对比
  10. linux中top命令详解
  11. 多线程之interrupt
  12. 角度&amp;弧度转换
  13. csv文件格式说明
  14. HDU 4725 The Shortest Path in Nya Graph(构图)
  15. iOS开发-UIRefreshControl下拉刷新
  16. iOS 11开发教程(八)定制iOS11应用程序图标
  17. ob_start()、ob_end_flush和ob_end_clean()多级缓冲
  18. No.6 - 利用 CSS animation 制作一个炫酷的 Slider
  19. 【bzoj4305】数列的GCD 组合数学+容斥原理
  20. 第六章 高级I/O函数

热门文章

  1. Esper系列(十四)Contained-Event Selection
  2. Jquery Form表单元素对象化
  3. 我用的Linux命令
  4. [iOS基础控件 - 5.4] 广告分页代码(UIScrollView制作)
  5. C#操作JSON学习
  6. jquery-ui 之draggable详解
  7. C#学习笔记(一):一些零散但重要的知识点汇总
  8. Java图片上传压缩处理
  9. Java split用法
  10. Fatal error: Using $this when not in object context in 解决方法