网络编程

  • 关注的是底层数据的传输;
  • 与网页编程不同,网页编程是关注与用户的数据交互。

概念:

  1. 网络:

    将不同区域的计算机连接到一起;区域(局域网,城域网,互联网)

  2. 地址:

    IP地址:
    确定网络上一个绝对地址,位置;——》房子的地址

  3. 端口号:
    区分计算机的软件——》房门 2个字节 0-65535 共65536个
    1、在同一个协议下 端口号不能重复;不同协议下可以重复
    2、1024以下的不要使用,给知名厂商预留的,如80——》 http;21——》ftp 尽量往大了指定

  4. 资源定位:
    URL统一资源定位符;URI:统一资源。

  5. 数据的传输

    1.协议:
    TCP和UDP两种协议
    1)TCP:面向连接,安全可靠;电话 类似于三次握手;效率低
    2)UDP:非面向连接,效率高;短信

    2.传输数据:
    1)先封装
    2)后拆封

在Java中所涉及的类主要包括:=========》类

  1. IP(地址,端口):InetAddress、netSocketAddress
  2. URL
  3. TCP: ServerSocket 、Socket
  4. UDP: DatagramSocket 、 DatagramPacket

Java中相关类的学习

网络编程相关的类与接口位于java.net包中

一、地址与端口
InetAddress类,封装计算机的IP地址和域名解析DNS,但是没有端口

需掌握的有:
该类没有公开的构造器,所以构造对象应使用本身提供的静态方法。
1)静态方法获取对象:
InetAddress.getLocalHost();产生一个本机的InetAddress对象
InetAddress.getByName(“IP地址或者域名”);通过IP或域名产生一个InetAddress对象
2)调用对象的方法:
getHostAddress();返回对象的IP地址
getHostName();返回对象的域名,若无或者不能解析,则返回IP地址

InetSocketAddress类,封装端口,在InetAddress类基础上 + 端口
1)含有对外构造器,故用构造方法产生对象:
InetSocketAddress(String hostname, int port);主机名与端口号构造对象
InetSocketAddress(InetAddress addr, int port);IP地址与端口号构造对象
2)调用对象的方法:
getAddress();返回IP地址IntAddress;
getHostName();返回域名hostname
getPort();返回端口号

构造端口的例子:

1.InetSocketAddress address = new InetSocketAddress(“127.0.0.1”,9999);
等价于:
2. Address = new InetSocketAddress(InetAddress.getByName(“127.0.0.1”),9999);

因为第一种方法的源码中就存在着将字符转化成为IP地址InetAddress的代码;故这两种方法是等价的。

二、 资源定位

URL包含四部分:协议+域名+端口号+资源文件名(/之后开始算,是相对路径)

URL类:
表示指向互联网资源的指针
1)创建对象:
URL(String spec);绝对路径构建
URL(URL context, String spec);相对路径构建
2)方法:
getProtocol();返回协议
getHost();返回域名
getPort();返回端口号
getFile();返回资源
getPath();获取相对路径
getRef();返回锚点
getQuery();返回参数;在有锚点情况下返回null;无锚点则返回正确
3)资源流
openStream();返回一个输入流InputStream

构建URL与使用方法的一个例子:
1.绝对URL

 url = new URL(“http://www.baidu.com:80/index.html#aa?uname=bjsxt”);

2.相对URL

url = new URL(“http://www.baidu.com:80/a/”);
url = URL(url, “b.txt”);
System.out.println(url.toString());     //http://www.baidu.com:80/a/b.txt
对第一种构建对象使用方法:
System.out.println(“协议:”+ url.getProtocol());       //协议:http
System.out.println(“域名:”+ url.getHost());       //域名:www.baidu.com
System.out.println(“端口:”+ url.getPort());       //端口:80
System.out.println(“资源:”+url.getFile());//资源:index.html#aa?uname=bjsxt
System.out.println(“相对路径:”+url.getPath());  //相对路径:index.html
System.out.println(“锚点:”+url.getRef());     // 锚点:aa?uname=bjsxt
System.out.println(“参数:”+url.getQuery());       //参数:有锚点返回null,若无锚点则返回uname=bjsxt

爬虫原理的一个例子:(爬虫第一步,先获取网页数据)

public static void main(String[] args){URL url = new URL(“http://www.baidu.com”);   //主页,默认资源//获取资源,网络流/* //直接这样读取的主页数据会存在乱码,主要是由于编码与解码的字符集不统一造成的,所以可以用转换流InputStream is = url.openStream();byte[] flush = new byte[1024];int len = 0;while((len=is.read(flush))!= -1){System.out.println(new String(flush,0,len));}is.close();*///使用转换流BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream(),”utf-8”));//也可以再定义写入流将读取到的内容直接写到文件中BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(baidu.html),”utf-8”));String msg = null;while((msg=br.readLine())!=null){System.out.println(msg); //直接打印出来内容bw.append(msg);bw.newLine();}bw.flush();bw.close();br.close();
}

三、UDP传输数据

UDP是以数据为中心的,非面向连接的,不安全,但效率高
根据数据传输的对象可分为客户端与服务器端;

在java种主要涉及到***DatagramSocket类***以及***DatagramPacket类***,其传输步骤分别为:
1.客户端
1)创建客户端对象,DatagramSocket类 + 指定端口
2)准备数据 字节数组
3)打包 DatagramPacket类 + 服务器地址及端口
4)发送数据
5)释放资源

2.服务器端
1)创建服务器对象,DatagramSocket类 + 指定端口
2)准备接收容器 字节数组 封装 DatagramPacket类
3)包 接收数据
4)分析数据
5)释放资源

服务器端与客户端使用的类是相同的,不过使用的方法有些不同:

DatagramSocket类 发送和接收数据报数据包的套接字。
1)创建对象 均使用DatagramSocket(int port)
2)方法
send(DatagramPacket p) 通过数据包p发送数据
receive(DatagramPacket p)从数据包p接收数据
close()关闭套接字,释放资源

DatagramPacket类 该类表示数据报包
数据封装与拆封操作均是DatagramPacket类,
客户端打包数据:

 DatagramPacket(byte[] buf, int offset, int length, SocketAddress address)//此处的SocketAddress是包含了接收端主机IP和端口的InetSocketAddress

服务端准备包接收数据:

 DatagramPacket(byte[] buf, int length)//主需要准备一个byte接收数组即可,不需要知道发送方的信息。

一般先写服务端,再写客户端:
服务端保存为:MyServer.java

public static void main(String[] args){//1、创建服务器端 + 端口DatagramSocket server = new DatagramSocket(8888);//2、准备接收容器DatagramPacket(byte[] buf, int length)byte[] container = new byte[1024];//3、封装成包 DatagramPacket(byte[] buf, int length)DatagramPacket packet = new DatagramPacket(container, container.length);//4、接收数据server.receive(packet);//5、分析数据byte[] data = packet.getData();int len = packet.getLength();System.out.println(new String(data,0,len));//6、释放资源server.close();
}

客户端保存为:MyClient.java

public static void main(String[] args){//1、创建客户端 + 端口DatagramSocket client = new DatagramSocket(6666);//2、准备数据String msg = “UDP编程”;byte[] data = msg.getBytes();//3、封装成包(指定发送地点及端口)DatagramPacket(byte[] buf, int length, SocketAddress address)DatagramPacket packet = new DatagramPacket(data,data.length,new InetSocketAddress(“localHost”,8888));//4、发送数据client.send(packet);//5、释放资源client.close();
}

上述实现的功能是将字符数组从客户端发送到服务端;而如何将其他类型的数据发送呢?
由于数据的传输只能一字节数组的形式,所以数据在打包和拆封时均需要进行相对应的转换;上述其实已经存在String——》byte[]的转换:byte[] data = msg.getBytes();以及相对应的byte[]——》String转换:new String(data,0,len)。

所以对于其他类型的数据,我们发送前也先要将其转换为byte[]形式,接收后也需要将其转化为原来的形式。

客户端的转换
转换方式double——》byte[] 字节数组 数据源 + Data输出流

public static byte[] convert(double num) throws IOException{byte[] data = null;ByteArrayOutputStream bos = new ByteArrayOutputStream();DataOutputStream dos = new DataOutputStream(bos);dos.writeDouble(num);dos.flush();//获取数据data = bos.toByteArray();dos.close();return data;
}

类型转换结束后再将客户端的步骤2修改为:

 double num = 89.12;byte[] data = convert(num);

服务端的转换
转换方式 字节数组——》double 字节数组+ Data输入流

public static double convert(byte[] data) throws IOException {DataInputStream dis = new DataInputStream(new ByteArrayInputStream(data));//获取数据double num = dis.readDouble();dis.close();return num;
}

完成转换后再将服务端的分析数据步骤5修改为:

 double data = convert(packet.getData());

四、TCP数据传输

TCP是面向连接的,安全,可靠,效率低;这个连接对服务端与客户端是同一个Socket。
1.面向连接Request—Response。
2.Socket编程

服务端ServerSocket类
1)构建对象:ServerSocket(int port)需指明端口
2)接收客户端连接:accept()阻塞式接收
3)发送数据;一个连接Socket相当于双向流,所以可以由Socket中getOutputStream()方法获得输出流OutputStream;

客户端Socket类
1)创建对象:Socket(String host, int port)指明服务器IP及端口;客户端本身不需要指明端口,由客户端自动分配。
客户端建立成功即表示建立了连接,一个接收accept()只能连接一次
2)接收数据:先使用Socket中getInputStream()方法获得输入流InputStream由于服务端与客户端的连接是同一个,所以两端对流进行包装时需要用同样的种类,即若服务端用BufferedWriter,则客户端要用BufferedReader;同样若服务端用DataOutputStream,则客户端也要用DataInputStream

如何在一个服务端创建多个客户端的连接?

若直接在服务端的接受连接accept()处建立循环,则实现的功能实际上是服务器先与一个客户端 建立连接,然后与之通信完毕后再与其他客户端建立连接。这样每个客户端之间并不是独立的,若一个客户端的连接出现阻塞式服务,则所有客户端均需等待。

实际上多个客户端连接需要的是每个客户端都能与服务器独立的发送,接收数据;并且客户端之间也是独立的;所以需要服务器为每一个客户端的连接创建一个线程,且需要为客户端的发送与接收分别创建一个线程。

简易聊天室原理:

先写服务器:Server01.java

public static void main(String[] args){//创建服务器ServerSocket server = new ServerSocket(9999);//接收服务端连接Socket client = server.accept();//写出数据//输入流DataInputStream dis = new DataInputStream(client.getInputStream());String msg = dis.readUTF();//输出流DataOutputStream dos = new DataOutputStream(client.getOutputStream());dos.writeUTF(“服务器——>” + msg);dos.flush();
}

再写客户端:Client01.java

public static void main(String[] args){//创建客户端Socket client = new Socket(“localhost”,9999);//创建控制台输入流BufferedReader console = new BufferedReader(new InputStreamReader(System.in));String info = console.readLine();//输出流DataOutputStream dos = new DataOutputStream(client.getOutputStream());dos.writeUTF(info);//输入流DataInputStream dis = new DataInputStream(client.getInputStream());String msg = dis.readUTF();System.out.println(msg);}

在Client01.java中,客户端只能单次读入,为了能多次读入信息并发送,需要进行循环,在循环中不需要重复建立流,所以可以将流单独出来,将其处理进行循环即可。

针对上述聊天室,客户端只能先读取控制台数据,然后发送数据,最后接收数据;服务端只能先接收数据,然后转发数据;即数据的收发并不是独立的,所以需要建立线程单独控制,如下:

先建立发送线程Send.java

public class Send implements Runnable{//控制台输入流private BufferedReader console;//输出流private DataOutputStream dos;//线程标识private boolean isRunning = true;//构造器public Send(){console = new BufferedReader(new InputStreamReader(System.in));}public Send(Socket client){this.Send();try{dos = new DataOutputStream(client.getOutputStream());}catch(IOException e){isRunning = false;CloseUtil.closeAll(dos, console);}}//1.从控制台接收数据public String getMsgFromConsole(){try{return console.readLine();}catch(IOException e){isRunning = false;CloseUtil.closeAll(dos, console);}return “”;}//将接收的数据发送出去public void send(){String msg = getMsgFromConsole();try{if(msg != null && !msg.equals(“”)){dos.writeUTF(msg);dos.flush();}}catch(IOException e){isRunning = false;CloseUtil.closeAll(dos, console);}}public void run(){//线程主体while(isRunning){send();}}}

然后在客户端处连接后直接建立新的线程即可:

new thread(new Send(client)).start();    //一条路径

类似的建立接收线程Receive.java

public class Receive implements Runnable{//输入流private DataInputStream dis;//线程标识private boolean isRunning = true;//构造器public Receive(){}public Receive(Socket client){try{dis = new DataInputStream(client.getInputStream());}catch(IOException e){isRunning = false;CloseUtil.closeAll(dis);}}//接收数据public String receive(){String msg = “”;try{msg = dis.readUTF();}catch(IOException e ){isRunning = false;CloseUtil.closeAll(dis);}return msg;}public void run(){//线程主体while(isRunning){System.out.println(receive());}}}

将关闭流的方法进行封装:CloseUtil.java

public class CloseUtil{public static void closeAll(Closeable… io){for(Closeable temp:io){try{if(temp !=null){temp.close();}}catch(Exception e){}}}
}

线程封装完毕后再将客户端进行修改Client02.java

public static void main(String[] args){//创建客户端Socket client = new Socket(“localhost”,9999);//创建输入线程new Thread(new Send(client)).start();//创建输入线程new Thread(new Receive(client)).start();
}

这样客户端在连接之后便可以任意发送与接收数据了,但是服务端目前还是只接受与转发数据一次,所以需要将服务端加一个循环。Server02.java

public static void main(String[] args){//创建服务器ServerSocket server = new ServerSocket(9999);//接收服务端连接Socket client = server.accept();//写出数据//输入流DataInputStream dis = new DataInputStream(client.getInputStream());//输出流DataOutputStream dos = new DataOutputStream(client.getOutputStream());while(true){String msg = dis.readUTF();dos.writeUTF(“服务器——>” + msg);dos.flush();}
}

这样便可以实现一个客户端与服务端任意的收发数据了,但是还不能实现多个客户端的连接。主要是因为服务端并没有为每个客户端的连接创建单独的线程,由于这个服务线程只有服务端使用,所以可以考虑在服务端建立内部类,创建如下:

服务端Server03.java

public class Server03{//为每个客户端创建一个容器private List< MyChannel > all = new ArrayList< MyChannel >();public static void main(String[] args){new Server03. channel();}//接收客户端线程服务public void channel(){//创建服务器ServerSocket server = new ServerSocket(9999);//接收服务端连接while(true){Socket client = server.accept();MyChannel channel = new MyChannel(client);all.add(channel); //将一条道路加入容器new Thread(channel).start();}}//内部类,处理客户端的线程private class MyChannel implements Runnable(){private DataInputStream dis;private DataOutputStream dos;private boolean isRunning = true;//构造器public MyChannel(){}public MyChannel(Socket client){try{dis = new DataInputStream(client.getInputStream());dos = new DataOutputStream(client.getOutputStream());}catch(IOException e){isRunning = false;CloseUtil.closeAll(dis,dos);all.remove(this):       //移除自身}}//接收数据pivate String receive(){String msg = “”;try{msg = dis.readUTF();}catch(IOException e){isRunning = false;CloseUtil.closeAll(dis);all.remove(this):      //移除自身}return msg;}//发送数据private void send(String msg){try{if(msg!=null && !msg.equals(“”)){dos.writeUTF(msg);dos.flush();}}catch(IOException e){isRunning = false;CloseUtil.closeAll(dos);all.remove(this):      //移除自身}}//发送给其他客户端private void sendOthers(){String msg = receive();for(MyChannel other : all){if(other == this){continue;}other.send(msg)}}public void run(){//线程主体while(isRunning){sendOthers();}}}}

这样便实现了客户端与服务器端的独立通信。

Java编程之路——网络编程篇相关推荐

  1. java 编程原理_Java网络编程 -- 网络编程基础原理

    Hello,今天记录下 Java网络编程 --> 网络编程基础原理. 一起学习,一起进步.继续沉淀,慢慢强大.希望这文章对您有帮助.若有写的不好的地方,欢迎评论给建议哈! 初写博客不久,我是杨展 ...

  2. Java面试知识点:网络编程

    问题:Java面试知识点:网络编程 答案: 1.InetAddress 代码如下: package com.xy;import java.net.InetAddress; import java.ne ...

  3. Python3 与 C# 网络编程之~ 网络基础篇

    最新版本查看:https://www.cnblogs.com/dotnetcrazy/p/9919202.html 入门篇 官方文档:https://docs.python.org/3/library ...

  4. java 网络编程 聊天_Java——网络编程(实现基于命令行的多人聊天室)

    目录: 1.ISO和TCP/IP分层模型 2.IP协议 3.TCP/UDP协议 4.基于TCP的网络编程 5.基于UDP的网络编程 6.基于TCP的多线程的聊天室的实现 1.ISO和TCP/IP分层模 ...

  5. 20165310 Java实验五《网络编程与安全》

    20165310 Java实验五<网络编程与安全> 任务一 题目:①编写MyBC.java实现中缀表达式转后缀表达式的功能:②编写MyDC.java实现从上面功能中获取的表达式中实现后缀表 ...

  6. Java并发编程实战_阿里P9整理分享的亿级流量Java高并发与网络编程实战PDF

    前言 为了帮助初级开发者快速掌握高并发.网络编程.微服务.海量数据的处理这些实用技术,本文以"理论+范例"的形式对各个知识点进行了详细的讲解,力争让读者在实践中快速掌握相关知识. ...

  7. Java学习——Day14:网络编程

    7.1 网络编程概述 Java是 Internet 上的语言,它从语言级上提供了对网络应用程 序的支持,程序员能够很容易开发常见的网络应用程序. Java提供的网络类库,可以实现无痛的网络连接,联网的 ...

  8. 阿里P9整理分享的亿级流量Java高并发与网络编程实战PDF

    前言 有人调侃我们说: 程序员不如送外卖.送外卖是搬运食物,自己是搬运代码,都不产出新的东西-- 透支体力,又消耗健康,可替代性极强,30岁之后就要面临被优化的危险-- 想跳槽,但是更高的平台难进,同 ...

  9. Java语言进阶:网络编程入门

    Java语言进阶:网络编程 网络编程入门 C/S C/S结构 :全称为Client/Server结构,是指客户端和服务器结构.常见程序有QQ.迅雷等软件. 特点: 客户端和服务器是分开的,需要下载客户 ...

最新文章

  1. linux后台运行python脚本
  2. 如何用excle制作黑人拉馆_小编教你如何用装机吧制作u盘启动盘
  3. 自定义sql_基于Calcite自定义SQL解析器
  4. yum更新php版本,yum php版本太低怎么办
  5. Codevs 2800 送外卖(状压DP)
  6. windows加linux双系统安装方法
  7. 思维导图模板创意可爱简单,模板资源分享
  8. python所需各种库(.whl)文件网址,不用下载其它运行库,直接pip install .....whl
  9. MySQL Error 1114
  10. 2021秋软工实践第一次个人编程作业
  11. mysql区间左开右闭_左开右闭区间怎么写
  12. 每日方法分享:免费一键抠图方法都有哪些?
  13. 数据预处理和特征工程1--无量纲化:数据归一化、标准化
  14. C语言实训 实训项目一 统计歌唱比赛成绩
  15. 渗透测试网络攻防--OSINT和被动侦察
  16. 【操作系统】进程-哲学家进餐问题
  17. 九度OJ 1260:珍珠项链 (字符串处理、DP)
  18. ROS节点开机自启动
  19. matlab雷达处理工具箱,GitHub - feng-zx/radar_tools: 雷达信号处理工具箱
  20. 冰点还原怎么关闭,不会的看这里

热门文章

  1. 安世亚太携手鑫精合,共推增材制造仿真技术应用与发展
  2. 单据模板显示公式使用
  3. 3D游戏建模师都学习什么?需要多少时间学成就业?
  4. 如何用 ModelScope 实现 “AI 换脸” 视频
  5. 计算机英语词汇合成词是什么意思,英语分类词汇常见合成词
  6. win10 触摸屏测试软件,Win10 测试版 18970 推送,微软着手改善触摸操作体验
  7. 这五种人工智能技术可以识别图片
  8. python通过银行卡号_python面向对象编程实例---银行账号
  9. 记录第一次写静态网页-百度首页
  10. pdf转图片(png高清)