Socket网络编程练习(C#)

news2024/9/21 12:31:15

Socket编程:两个窗口通信

本文章代码来自b站视频:【.Net零基础入门 (老赵主讲)-哔哩哔哩】 https://b23.tv/YI5VWaj

原视频发布者为传智播客,本人根据自己的学习进度对代码做了少许优化

一、网络编程前置知识

1.1 什么是网络编程

  • 网络编程从大的方面说就是对信息的发送到接收,中间传输为物理线路的作用。

    网络编程最主要的工作就是在发送端把信息通过规定好的协议进行组装包,在接收端按照规定好的协议把包进行解析,从而提取出对应的信息,达到通信的目的。中间最主要的就是数据包的组装,数据包的过滤,数据包的捕获,数据包的分析,当然最后再做一些处理,代码、开发工具、数据库、服务器架设和网页设计这5部分你都要接触。

1.2 Socket简介

  • 用视频的话讲解就是宿管大妈

    如图男生要找一个女生,首先要知道宿舍楼位置(服务器ip地址),但是知道ip地址并不能直接找到要找的女生,还需要知道女生的名字(应用的端口号),这两样东西都是被宿管大妈(Socket)管理的

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传在这里插入图片描述

    宿管大妈主要是根据男生提供的女生姓名找到女生,负责的是监听。

    通信的Socket是应用自身携带的,可以理解男生和女生的通信是用的自己的嘴说话和耳朵进行信息交流,在程序中我们要为客户端和服务器分别绑定一个Socket负责通信

1.3 协议

  • 协议的本质就是约定,语言本身就有约定的存在,比如数字“2”代表数量为二的含义,数字“1”代表数量为一的含义。我们更改一下,让“2”这个字符代表数量一,让“1”代表数量二,如果大家都认可这个约定,我们以后数数就是“213456789…”,对于计算机来说,并不能直接识别字符本身的含义,我们通常在数据的指定位置上加标志位来解决这个问题。比如“0”代表文本信息,“1”代表文件数据,“2”代表动作信息。而网络协议TCP/IP要比我们在本程序中规定的要复杂的多,但是基本原理是一致的。想要深入学习TCP/IP,请参照《计算机网络》这门课程。

二、开始项目

2.1 程序流程图

  • 原版流程图是简化的

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传在这里插入图片描述

  • 自己绘制的流程图
    在这里插入图片描述

2.2 新建项目

  • 新建winform(.NET Framework)项目

    本人使用的是Visual Studio2022版本,不同版本的Visual Studio操作有细微的区别,没有相关依赖的需要安装。安装方式:工具->获取工具和功能->visual studio installer->选择.NET桌面开发->点击安装。其他版本的请自行百度安装方法或者更换版本。

    第一个项目是server端的编写

  • server端页面布局

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传在这里插入图片描述

2.3 第一步:初始化服务器

  • 点击监听按钮,开始监听
    /// <summary>
    /// 开始监听按钮点击事件,开始监听:
    /// 1.创建监听Socket对象
    /// 2.绑定服务器ip和端口号
    /// 3.开启监听
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void startListenBtn_Click(object sender, EventArgs e)
    {
    
    	try { 
    		//点击开始监听,服务器创建负责监听IP地址与端口号的Socket
    		Socket socketListener=new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    	   
    		IPAddress ip=IPAddress.Any;
    
    		//创建端口号对象,IPAddress.Any表示服务器接收任意ip地址的访问
    		IPEndPoint endPoint = new IPEndPoint(ip, Convert.ToInt32(portBox.Text));
    		socketListener.Bind(endPoint);
    
    		ShowMsg("监听成功");
    
    		//设置时间点内最大访问数
    		socketListener.Listen(10);
    
    		//由于监听是个死循环,创建监听函数,需要开启新线程调用它,避免主线程卡死
    		Thread thred=new Thread(Listen);
    		thred.IsBackground = true;
    		thred.Start(socketListener);
    	}
    	catch { }
    }
    
    /// <summary>
    /// 监听函数
    /// 1.接收监听Socket
    /// 2.创建死循环,表示监听一直处于开启状态
    /// 3.通过Accept函数获取服务器端的负责通信的Socket
    /// 注:注释的代码是后序功能需要的代码,现在注释是进度需要
    /// </summary>
    /// <param name="o"></param>
    void Listen(object o)//被线程所执行的函数所携带的参数必须为object类型
    {
    	Socket socketListener = o as Socket;
    	 
    	// 等待客户端的连接,并且创建与之通信的socket
    	while (true) {
    		Socket socketCom = socketListener.Accept();
    		/*socketDics.Add(socketCom.RemoteEndPoint.ToString(), socketCom);*/
    
    		//将ip地址和端口号存入下拉框
    		serverSelectComboBox.Items.Add(socketCom.RemoteEndPoint.ToString());
    		ShowMsg(socketCom.RemoteEndPoint.ToString() + ":" + "连接成功");
    
    		/*Thread thred = new Thread(showReceivedMsg);
    		thred.IsBackground = true;
    		thred.Start(socketCom);*/
    	}
    }
    
    /// <summary>
    /// log数据显示
    /// </summary>
    /// <param name="msg"></param>
    void ShowMsg(string msg)
    {
    	logBox.AppendText(msg+"\r\n");
    }
    

2.4 第二步:初始化客户端

  • 客户端布局

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传在这里插入图片描述

  • 连接服务器代码

    /// <summary>
    /// 连接按钮点击事件,连接到服务器:
    /// 1.创建通信的的Socket
    /// 2.从输入框获取ip地址和port
    /// 3.通过Connect函数连接到服务器
    /// 注:注释的代码是后序功能需要的代码,现在注释是进度需要
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    Socket socketSend;//全局变量,方便后面使用
    private void connectBtn_Click(object sender, EventArgs e)
    {
    	try
    	{
    		//创建负责通信的Socket
    		socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
    		IPAddress ip = IPAddress.Parse(ipAddressBox.Text);
    		EndPoint serverEndPoint = new IPEndPoint(ip, Convert.ToInt32(portBox.Text));
    
    		//连接远程服务器的应用端口号,connect返回的始终为空
    		socketSend.Connect(serverEndPoint);
    		ShowMsg("成功连接服务器:" + serverEndPoint);
    
    		/*Thread thred = new Thread(showReceivedMsgFromServer);
    		thred.IsBackground = true;
    		thred.Start(socketSend);*/
    	}
    	catch
    	{
    		ShowMsg("not connected!");
    	}
    }
    
    void ShowMsg(string msg)
    {
    	logBox.AppendText(msg+"\r\n");
    }
    
  • 程序运行效果
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传在这里插入图片描述

2.5 第三步:客户端向服务器发送信息

  • 服务器端代码

    void Listen(object o)
    {
    	Socket socketListener = o as Socket;
    	 
    	// 等待客户端的连接,并且创建与之通信的socket
    	while (true) {
    		Socket socketCom = socketListener.Accept();
    		/*socketDics.Add(socketCom.RemoteEndPoint.ToString(), socketCom);*/
    
    		//将ip地址和端口号存入下拉框
    		serverSelectComboBox.Items.Add(socketCom.RemoteEndPoint.ToString());
    		ShowMsg(socketCom.RemoteEndPoint.ToString() + ":" + "连接成功");
    
    		//打开注释,服务器接收消息也是死循环,所以需要开启新线程调用
    		Thread thred = new Thread(showReceivedMsg);
    		thred.IsBackground = true;
    		thred.Start(socketCom);
    	}
    }
    
    /// <summary>
    /// 接收数据
    /// 1.接收通信Socket
    /// 2.开启死循环表示服务器接收处于开启状态
    /// 3.开始接收数据,接收方法涉及到IO流知识,不熟悉的同学可以查阅官方文档
    ///     文档地址:https://learn.microsoft.com/zh-cn/dotnet/csharp/
    /// 4.消息框(logBox)显示信息
    /// </summary>
    /// <param name="o"></param>
    void showReceivedMsg(object o)
    {
    	Socket socketCom=o as Socket;
    	while (true)
    	{
    		try { 
    			byte[] buffer = new byte[1024 * 1024 * 2];
    
    			//实际接收到的有效字节数,接收到数据的同时会给数组赋值
    			int availableBytes = socketCom.Receive(buffer);
    
    			//解码
    			if (availableBytes == 0){ break; }
    			string receivedMessage = Encoding.UTF8.GetString(buffer, 0, availableBytes);
    			ShowMsg(socketCom.RemoteEndPoint.ToString() + ":" + receivedMessage);
    		}
    		catch { }
    	}
    }
    
  • 客户端代码

    /// <summary>
    /// 发送按钮点击事件,客户端给服务器发送信息
    /// 1.获取文本信息
    /// 2.把信息编码(字节数组)
    /// 3.发送数据
    /// 4.清空消息发送框
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void sendMsgBtn_Click(object sender, EventArgs e)
    {
    	//获取数据
    	string msg = msgBox.Text.Trim();
    	byte[] data = Encoding.UTF8.GetBytes(msg);
    
    	//发送数据
    	socketSend.Send(data);
    	msgBox.Clear();
    }
    
  • 程序运行效果
    在这里插入图片描述

    在这里插入图片描述

2.5 第四步:服务器向指定的服务器客户端发送信息

  • 客户端代码

    private void connectBtn_Click(object sender, EventArgs e)
    {
    	try
    	{
    		//创建负责通信的Socket
    		socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
    		IPAddress ip = IPAddress.Parse(ipAddressBox.Text);
    		EndPoint serverEndPoint = new IPEndPoint(ip, Convert.ToInt32(portBox.Text));
    
    		//连接远程服务器的应用端口号,connect返回的始终为空
    		socketSend.Connect(serverEndPoint);
    		ShowMsg("成功连接服务器:" + serverEndPoint);
    
    		//打开注释
    		Thread thred = new Thread(showReceivedMsgFromServer);
    		thred.IsBackground = true;
    		thred.Start(socketSend);
    	}
    	catch
    	{
    		ShowMsg("not connected!");
    	}
    }
    
    /// <summary>
    /// 信息接收方法
    /// 1.创建缓冲池
    /// 2.判断标志位,判断标志位是为了后面区分接收的信息类型,方便扩展
    /// 3.解码
    /// 4.显示消息
    /// </summary>
    /// <param name="o"></param>
    void showReceivedMsgFromServer(object o)
    {
    	Socket socketCom=o as Socket;
    	while (true)
    	{
    		try { 
    			byte[] buffer = new byte[1024 * 1024 * 5];
    		   
    			//实际接收到的有效字节数,同时会给buffer数组赋值
    			int availableBytes = socketCom.Receive(buffer);                   
    			byte flagBit = buffer[0];
    			
    			//解码
    			if (availableBytes == 0) { break; }
    
    			switch (flagBit) { 
    				case 0:
    					ShowMsg("标志位是" + flagBit + "您接收的是文本消息");
    					string receivedMessage = Encoding.UTF8.GetString(buffer, 1, availableBytes-1);
    					ShowMsg(socketCom.RemoteEndPoint.ToString() + ":" + receivedMessage);
    					break;
    				case 1:
    					break;
    				case 2:
    					break; 
    				default:
    					break;
    			}		
    		}
    		catch{break;}
    	}
    }
    
  • 服务器的代码

    //存储连接到服务器的socket
    Dictionary<string, Socket> socketDics = new Dictionary<string, Socket>();
    
    void Listen(object o)//被线程所执行的函数所携带的参数必须为object类型
    {
    	Socket socketListener = o as Socket;
    	 
    	// 等待客户端的连接,并且创建与之通信的socket
    	while (true) {
    		Socket socketCom = socketListener.Accept();
    		
    		//打开注释,将数据存入字典
    		socketDics.Add(socketCom.RemoteEndPoint.ToString(), socketCom);
    
    		//将ip地址和端口号存入下拉框
    		serverSelectComboBox.Items.Add(socketCom.RemoteEndPoint.ToString());
    		ShowMsg(socketCom.RemoteEndPoint.ToString() + ":" + "连接成功");
    
    		//打开注释
    		Thread thred = new Thread(showReceivedMsg);
    		thred.IsBackground = true;
    		thred.Start(socketCom);
    	}
    }
    
    /// <summary>
    /// 发送消息按钮点击事件,向客户端发送数据:
    /// 1.获取数据
    /// 2.添加标志位
    /// 3.添加信息位
    /// 4.根据下拉框的选择获取ip和端口号
    /// 5.根据ip和端口号从字典中获取通信的Socket
    /// 6.发送消息
    /// 7.清空消息发送框
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void sendMessageBox_Click(object sender, EventArgs e)
    {
    	try
    	{
    		string msg = messageBox.Text;
    		List<byte> dataList = new List<byte>();
    		byte[] data = Encoding.UTF8.GetBytes(msg);
    
    		//标志位
    		dataList.Add(Constant.STRING_FLAG);
    
    		//信息位
    		dataList.AddRange(data);
    
    		//获取通信的socket
    		string serverEndPoint = serverSelectComboBox.SelectedItem.ToString();
    		Socket socketCom = socketDics[serverEndPoint];
    
    		//发送信息
    		if (socketCom != null) socketCom.Send(dataList.ToArray());
    		messageBox.Clear();
    	}catch { }
    }
    
    //常量池,便于维护
    class Constant
    {
    	public const byte STRING_FLAG = 0;
    	public const byte FILE_FLAG = 1;
    	public const byte ACTION_FLAG = 2;
    }
    
  • 程序运行效果
    在这里插入图片描述
    在这里插入图片描述

2.5 第五步:完善剩余功能:文件,窗口抖动

  • 服务器代码

    /// <summary>
    /// 选择按钮点击事件,选择要发送的文件
    /// 1.创建打开文件对话框对象
    /// 2.设置目录
    /// 3.设置属性
    /// 4.打开对话框
    /// 5.选择文件,把文件名显示到文件框里面
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void selectFileBtn_Click(object sender, EventArgs e)
    {
    	OpenFileDialog ofd = new OpenFileDialog();
    	ofd.InitialDirectory = @"E:\old Downloads\迅雷下载";
    	ofd.Title = "选择文件";
    	ofd.Filter = "所有文件|*.*";
    	ofd.ShowDialog();
    
    	fileNameBox.Text = ofd.FileName;
    }
    
    /// <summary>
    /// 发送文件按钮点击事件,点击后向客户端发送文件
    /// 1.从文件文本框从获取文件目录
    /// 2.创建文件流
    /// 3.创建数据缓冲区
    /// 4.读取文件
    /// 5.创建List
    /// 6.List设置标志位
    /// 7.List存放信息数组
    /// 8.从字典获取通信Socket
    /// 9.发送文件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void sendFileBtn_Click(object sender, EventArgs e)
    {
    	try
    	{
    		string filePath = fileNameBox.Text;
    		if (filePath == null) { ShowMsg("未选择文件"); }
    		else { 
    			//using 语句定义一个范围,在此范围的末尾将释放对象。
    			using (FileStream fileRead = new FileStream(filePath, FileMode.Open, FileAccess.Read))
    			{
    				List<byte> fileData = new List<byte>();
    				byte[] data = new byte[1024 * 1024 * 5];
    
    				//将数据存入缓冲区,并返回读取的长度,读取的同时会向data数组中传入数据
    				int availableLength = fileRead.Read(data, 0, data.Length);
    
    				fileData.Add(Constant.FILE_FLAG);
    				fileData.AddRange(data);
    
    				//发送文件
    				Socket socketCom = socketDics[serverSelectComboBox.SelectedItem.ToString()];
    				if (socketCom == null) ShowMsg("未选择ip地址");
    				else socketCom.Send(fileData.ToArray(), 0, availableLength + 1, SocketFlags.None);
    			}
    		}
    	}
    	catch { }
    }
    
    /// <summary>
    /// 发送窗口抖动
    /// 窗口抖动只需要发送标志位,不需要额外信息
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void action_Click(object sender, EventArgs e)
    {
    	try
    	{
    		byte[] actionData = { Constant.ACTION_FLAG };
    		Socket socketCom = socketDics[serverSelectComboBox.SelectedItem.ToString()];
    		if (socketCom == null) ShowMsg("未选择ip地址");
    		else socketCom.Send(actionData);
    	}catch { }
    }
    
  • 客户端代码

    void showReceivedMsgFromServer(object o)
    {
    	Socket socketCom=o as Socket;
    	while (true)
    	{
    		try { 
    			byte[] buffer = new byte[1024 * 1024 * 5];
    		   
    			//实际接收到的有效字节数
    			int availableBytes = socketCom.Receive(buffer);                   
    			byte flagBit = buffer[0];
    			
    			//解码
    			if (availableBytes == 0) { break; }
    
    			switch (flagBit) { 
    				case 0:
    					/* ...接收文本信息的代码 */
    					break;
    				case 1:
    					ShowMsg("标志位是" + flagBit + "您接收的是文件类型的数据");
    					//弹出保存窗口
    					SaveFileDialog saveFileDialog = new SaveFileDialog();
    					string path = InitSaveFileDialog(saveFileDialog);
    					using (FileStream fileWrite=new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write))
    					{
    						fileWrite.Write(buffer, 1, availableBytes - 1);
    					}
    					ShowMsg("文件保存成功");
    					break;
    				case 2:
    					ShakingForm();
    					break;
    				default:
    					break;
    			}	
    		}
    		catch{break;}
    	}
    }
    
    private string InitSaveFileDialog(SaveFileDialog saveFileDialog)
    {
        saveFileDialog.InitialDirectory = @"E:\old Downloads\迅雷下载";
        saveFileDialog.Filter = "所有文件|*.*";
        saveFileDialog.Title = "保存文件";
        saveFileDialog.ShowDialog(this);		
        return saveFileDialog.FileName;
    }
    
    private void ShakingForm()
    {
    	for(int i = 0; i < 500; i++)
    	{
    		this.Location = new Point(200, 200);
    		this.Location = new Point(210, 210);
    	}
    }      
    

三、注意事项

3.1 本机ip地址

  • 每个人电脑的ip地址可以自己更改,所以地址会发生变动,查看本机ip方法:

    打开cmd命令行窗口,输入命令ipconfig /all

3.2 线程冲突

  • 线程冲突问题需要在form的加载事件中解决,取消线程检查。单击窗体进入Load事件

    private void SocketClientForm_Load(object sender, EventArgs e)
    {
    	Control.CheckForIllegalCrossThreadCalls = false;
    }
    
     private void SocketCommunication_Load(object sender, EventArgs e)
    {
    	//代码用来防止多线程错误,如果出现多线程错误,可以打开这个注释
    	//Control.CheckForIllegalCrossThreadCalls = false;
    }
    

3.3 传输文件大小问题

  • 本程序不能传输过大的文件,这需要更高级的知识

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/453545.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Leetcode每日一刷】动态规划:509. 斐波那契数、322. 零钱兑换、300. 最长递增子序列

博主简介&#xff1a;努力学习的22级计科生博主主页&#xff1a; 是瑶瑶子啦所属专栏: LeetCode每日一题–进击大厂 前言&#xff1a;动规五部曲 以下是《代码随想录》作者总结的动规五部曲 确定dp数组&#xff08;dp table&#xff09;以及下标的含义确定递推公式&#xff0…

什么是异步,同步,并行,串行,单工,半双工,全双工通信

目录 1 如何理解“BUS总线” 2 通信方式的分类 2.1 串行通信Serial communication 2.1.1 异步传输Asynchronous serial communication 2.1.2 同步传输Synchronous serial communication 2.1.3 单工通信Simplex communication 2.1.4 半双工通信Half-duplex communication…

Unity API详解——Matrix4x4类

在脚本中通常用Vector3、QUaternion、Transform等类的属性和方法来对物体进行变换&#xff0c;Matrix4x4类通常在一些比较特殊的地方&#xff0c;如对摄像机的非标准投影变换等。本博客主要介绍Matrix4x4类的一些实例和静态方法。 文章目录 一、Matrix4x4类实例方法1、Multply…

机器学习实战教程(九):模型泛化

泛化能力 模型泛化是指机器学习模型对新的、未见过的数据的适应能力。在机器学习中&#xff0c;我们通常会将已有的数据集划分为训练集和测试集&#xff0c;使用训练集训练模型&#xff0c;然后使用测试集来评估模型的性能。模型在训练集上表现得好&#xff0c;并不一定能在测…

Redis源码分析(基于Redis7,对比Redis6)

PS: redis7.0.9版本的 1.Redis 源代码分类 1.1Redis 基本的数据结构 基础 Redis对象object.c字符串t_string.c列表t_list.c字典t_hash.c集合及有序集合t_set.c和z_set.c数据流 t_stream 底层实现结构 listpack.c 和 rax.c 简单动态字符串 sds.c整数集合 intset.c压缩列表 z…

【dp】最长递增子序列

文章目录 方法一&#xff1a;动态规划方法二&#xff1a;贪心 二分查找构造最长递增子序列 方法一&#xff1a;动态规划 dp[i]&#xff1a;末尾元素为arr[i]的最长子序列的长度 从0遍历到i - 1&#xff0c;若遍历到的元素小于当前值arr[i]&#xff0c;表示当前值arr[i]可以和…

国考省考行测:词句理解,词的对象指代,就近原则,主语一致法,语意语境分析上下文找出指代含义

国考省考行测&#xff1a;词句理解&#xff0c;词的对象指代&#xff0c;就近原则&#xff0c;主语一致法&#xff0c;语意语境分析上下文找出指代含义 2022找工作是学历、能力和运气的超强结合体! 公务员特招重点就是专业技能&#xff0c;附带行测和申论&#xff0c;而常规国…

3年100亿!苏宁易购与倍科达成重磅战略合作

紧抓消费复苏机遇&#xff0c;家电行业迎来重磅合作。4月20日&#xff0c;苏宁易购与国际知名家电品牌倍科在南京召开战略合作发布会&#xff0c;共同宣布升级战略合作伙伴关系。双方将围绕3年100亿战略合作目标开展独家品牌授权、发起“BIS”计划、打造生态开放平台、升级用户…

5G基站外市电改造建设方案 (ppt可编辑)

本资料来源公开网络&#xff0c;仅供个人学习&#xff0c;请勿商用&#xff0c;如有侵权请联系删除 外市电定义及分类 定义&#xff1a;由供电部门提供的专用高压电源或非专用高压电源或低压电源均称为市电。分类&#xff1a; &#xff08;1&#xff09;按电压等级分类 ①提供…

贝叶斯学习(Bayesian Learning)基础篇

Bayesian Learning 前言Motivation and IntroductionThink about Spam Filtering.先验概率后验概率似然度边际概率 Basic assumptionRelevancePractical diculties Bayes TheoremProbability: random eventsBayesian Learning Maximum A Posteriori HypothesisBayes Optimal Cl…

合同管理的6个最佳实践

合同管理不善会使你的合同流程效率低下&#xff0c;并产生负面影响&#xff1a; -收入损失 谈判缓慢、审批延迟和里程碑缺失等低效合同代价高昂。如果没有办法自动跟踪最后期限&#xff0c;并得到通知来执行时间敏感的行动&#xff0c;就会有错过最后期限的风险。 -协作和…

数组【有点难,要注重实战】

目录 1. 一维数组的创建和初始化1.1 数组的创建1.2 数组的初始化1.3 一维数组的使用1.4 一维数组在内存中的存储 2. 二维数组的创建和初始化2.1 二维数组的创建2.2 二维数组的初始化2.3 二维数组的使用2.4 二维数组在内存中的存储 3. 数组越界4. 数组作为函数参数4.1 冒泡排序函…

JavaEE-一文了解IP协议与IP地址

目录 IP协议什么是IP地址IP地址的组成动态分配IPNAT机制(网络地址转换) IP协议 IP协议是不可靠、无连接的 不可靠:表示IP协议不能保证IP数据报能成功的到达目的地。IP仅提供传输服务&#xff0c;任何可靠性的要求都必须由上层来提供&#xff08;如TCP&#xff09;。如果传输过…

【C++|排序算法】冒泡、快排、归并、堆排序算法模版

目录 简介冒泡排序快速排序归并排序堆排序结语简介 Hello! 非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出~ ଘ(੭ˊᵕˋ)੭ 昵称:海轰 标签:程序猿|C++选手|学生 简介:因C语言结识编程,随后转入计算机专业,获得过国家奖学金,有幸在竞赛中拿过一些国…

字节跳动五面都过了,结果被刷了,问了hr原因竟说是...

摘要 说在前面&#xff0c;面试时最好不要虚报工资。本来字节跳动是很想去的&#xff0c;几轮面试也通过了&#xff0c;最后没offer&#xff0c;自己只想到几个原因&#xff1a;1、虚报工资&#xff0c;比实际高30%&#xff1b;2、有更好的人选&#xff0c;这个可能性不大&…

反垃圾邮件产品技术要求

声明 本文是学习信息安全技术 反垃圾邮件产品技术要求和测试评价方法. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 反垃圾邮件产品技术要求 引言 为指导反垃圾邮件产品的研制、生产、测试和评价工作的开展&#xff0c;本标准依据《信息技术 安全技…

基于Spring注解 + MyBatis + Servlet 实现数据库交换的小小Demo

基于Spring注解 MyBatis Servlet 实现数据库交换的小小Demo 第一步 创建web 项目&#xff0c;这一步省略&#xff0c;有不会的可以参考之前发布的文档 第二步 配置pom.xml文件 <dependencies><!-- Spring常用依赖 --><dependency><groupId>org.spr…

SpringCloud --- Eureka注册中心

一、场景 假如我们的服务提供者user-service部署了多个实例&#xff0c;如图 思考几个问题&#xff1a; order-service在发起远程调用的时候&#xff0c;该如何得知user-service实例的ip地址和端口&#xff1f; 有多个user-service实例地址&#xff0c;order-service调用时该…

【LeetCode】剑指 Offer 67. 把字符串转换成整数 p318 -- Java Version

题目链接&#xff1a;https://leetcode.cn/problems/ba-zi-fu-chuan-zhuan-huan-cheng-zheng-shu-lcof/ 1. 题目介绍&#xff08;67. 把字符串转换成整数&#xff09; 写一个函数 StrToInt&#xff0c;实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。 …

day1 什么是互联网

目录 计算机网络的定义与分类 网络的网络 互联网的组成 互联网的边缘部分 互联网基础结构发展的三个阶段 第一阶段&#xff08;1969 - 1990&#xff09; 第二阶段&#xff08;1985 - 1993&#xff09; 第三阶段&#xff08;1993 - 现在&#xff09; 20世纪90年代&#xff…