一、网络基础
- 网络通信:
- 网络通信的概念:两台设备之间通过网络实现数据传输
- 网络通信:将数据通过网络从一台设备传输到另一台设备
- java.net包下提供了一系列的类和接口,供程序员使用,完成网络通信
- 网络:
- 概念:两台或多台设备通过一定的物理设备连接起来构成了网络
- 根据网络的覆盖范围不同,对网络进行分类:(1)局域网:覆盖范围最小,仅仅覆盖一个教室或一个机房或一个公司(2)城域网:覆盖范围较大,可以覆盖一个城市(3)广域网:覆盖范围最大,可以覆盖全国,甚至全球,万维网是广域网的代表
- ip地址:
- 概念:用于唯一标识网络中的每台主机/计算机
- 查看ip地址:ipconfig
- ip地址的表示形式:点分十进制 xx.xx.xx.xx
- 每一个十进制数的范围0~255
- ip地址的组成=网络地址+主机地址,比如:192.168.16.69(192.168.16代表网络地址)
- IPv6是用于替代IPv4的下一代IP协议,其地址数量号称可以为世界上的每一粒沙子编上一个地址
- 由于IPv4最大的问题在于网络地址资源有限,严重制约了互联网的应用和发展。IPv6的使用,不仅能解决网络地址资源数量的问题,而且也解决了多种接入设备连入互联网的障碍
- IPv6使用128位(16个字节)表示一个地址。xx:xx:xx:xx:xx:xx:xx:xx(每个xx代表两个字节)
- IPv4地址分类(1)A类地址:1个字节代表网络号(网络号第一位固定为0),3个字节代表主机号(2)B类地址:2个字节代表网络号(网络号前两位固定为10),2个字节代表主机号(3)C类地址:3个字节代表网络号(网络号前三位固定为110),1个字节代表主机号(4)暂时不关注比较特殊的D类和E类地址(5)127.0.0.1表示本机地址
- 地址的表示范围(第一个字节)(1)A类地址:0~127(2的7次方-1,因为有一位是固定的)(2)B类地址:128~191(B类地址是从128开始,128+0~128+63,2的6次方-1等于63)(3)C类地址:192~223(C类地址是从192开始,192+0~192+31,2的5次方-1等于31)
- 域名:
- www.baidu.com
- 好处:为了方便记忆,解决记ip地址的困难
- 概念:将ip地址映射成域名
- 端口号:
- 概念:用于标识计算机上某个特定的网络程序(一个电脑上可以同时运行多个服务)
- 表示形式:以整数形式,范围0~65535(同一个主机上两个不同的服务不能占用相同的端口)(两个字节表示端口,2的16次方-1就是65535)
- 0~1024已经被占用,比如ssh 22,ftp 21,smtp 25,http 80。因此,在网络开发中,不要使用0~1024的端口
- 常见的网络程序端口号:(1)Tomcat 8080(2)mysql 3306(3)oracle 1521(4)sqlserver 1433
- 网络协议:
- 举例理解协议这个概念:人和人交流通过语言,语言本身就是一种协议
- 在网络编程中,数据的组织形式就是协议
- TCP/IP协议(Transmission Control Protocol/Internet Protocol),中文译名为传输控制协议/因特网互联协议,又叫网络通讯协议,这个协议是Internet最基本的协议。简单地说,它就是由网络层的IP协议和传输层的TCP协议组成的
- 网络通信协议:
OSI模型 TCP/IP模型 TCP/IP模型各层对应的协议 应用层 应用层 HTTP、ftp、telnet、DNS... 表示层 会话层 传输层 传输层(TCP) TCP、UDP... 网络层 网络层(IP) IP、ICMP、ARP... 数据链路层 物理层+数据链路层 Link 物理层
- TCP协议(传输层):
- 使用TCP协议前,需要先建立TCP连接,形成传输数据通道
- 传输前,采用“三次握手”方式。是可靠的(三次握手理解:(1)A跟B说了一句话(2)A需要知道自己说的话是否被B听到,所以B回了A一句(3)B需要知道自己说的话是否被A听到,因此A还要回B一句话)
- TCP协议进行通信的两个应用进程:客户端、服务端
- 在连接中可进行大数据量的传输
- 传输完毕,需要释放已经建立的连接,效率低
- UDP协议(传输层):
- 将数据、源、目的封装成数据包,不需要建立连接
- 每个数据报的大小限制在64K内,不适合传输大量的数据
- 因无需建立连接,故是不可靠的
- 发送数据结束时,无需释放资源(因为没有建立连接),速度快
二、InetAddress
- InetAddress类的常用方法:
getLocalHost 获取本机的InetAddress对象 getByName 根据指定的主机名/域名获取InetAddress对象 getHostName 获得InetAddress对象的主机名
getHostAddress 获得InetAddress对象的地址 - 应用案例演示:
package com.study; import java.net.InetAddress; import java.net.UnknownHostException; //演示InetAddress类的使用 public class API_ { public static void main(String[] args) throws UnknownHostException { //1.获取本机的InetAddress对象 InetAddress localHost = InetAddress.getLocalHost(); //可以获取到 本机的主机名/本机的ip地址 System.out.println(localHost); //2.根据指定的主机名,获取InetAddress对象 InetAddress localHost2 = InetAddress.getByName("这里填写自己的主机名"); //localHost2和localHost的输出结果一样 System.out.println(localHost2); //3.根据域名返回InetAddress对象 InetAddress host = InetAddress.getByName("www.baidu.com"); //可以获取到 域名/ip地址 System.out.println(host); //4.通过一个InetAddress对象,获取它对应的ip地址 String ipAddress = localHost2.getHostAddress(); System.out.println(ipAddress); //5.通过一个InetAddress对象,获取它对应的主机名或者是域名 String name = localHost2.getHostName(); System.out.println(name); } }
- 这些API的作用(1)获取本机的信息【主机名/IP】(2)通过域名获取远程服务器的【域名/IP】
三、Socket
- Socket的基本介绍:
- 套接字(Socket)开发网络应用程序被广泛采用,以至于成为事实上的标准
- 通信的两端都要有Socket,是两台机器间通信的端点
- 网络通信实际上就是Socket之间的通信
- Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输
- 一般主动发起通信的应用程序称为客户端,等待请求通信的为服务端
- 示意图:
- 当我们需要通讯时(读写数据):
- socket.getOutputStream()
- socket.getInputStream()
- 客户端和服务器在通常情况下,是在不同主机的。但在我们学习该部分知识时,客户端和服务器在一台主机
四、TCP编程
(1)TCP网络通信编程基本介绍
-
基于客户端——服务端的网络通信
-
底层使用的是TCP/IP协议
-
应用场景举例:客户端发送数据,服务端接收并显示在控制台
-
基于Socket的TCP编程
(2)TCP网络通信编程
- 应用案例1演示(使用字节流)(1)编写一个客户端和一个服务器端(2)服务器端在9999端口监听(注意:当没有客户端连接9999端口时,程序会阻塞,等待连接)(3)客户端连接到服务器端,发送“hello,server”,然后退出(4)服务器端接收到客户端发送的信息,输出,并退出
//服务端代码 package com.study.socket; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; public class SocketTCP01Server { public static void main(String[] args) throws IOException { //1.在本机的9999端口监听,等待连接 //一定要确保本机没有其它服务占用9999端口 ServerSocket serverSocket = new ServerSocket(9999); //2.当没有客户端连接9999端口时,程序会阻塞,等待连接 //如果有客户端连接,则会返回Socket对象,程序继续往下执行 //这个socket就是服务器的socket Socket socket = serverSocket.accept(); //3.通过输入流,读取客户端写入到数据通道的数据,并在控制台显示 InputStream inputStream = socket.getInputStream(); //4.因为不是BufferedInputStream,所以我们要自己设置缓冲 byte[] b = new byte[1024]; int readLen = 0; while((readLen = inputStream.read(b)) != -1){ System.out.print(new String(b,0,readLen));//根据读取到的实际长度显示内容 } //5.关闭流和Socket inputStream.close(); socket.close(); //6.服务器端还要多关闭一个ServerSocket serverSocket.close(); } }
//客户端代码 package com.study.socket; import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; public class SocketTCP01Client { public static void main(String[] args) throws IOException { //1.连接服务器(ip,端口) //因为目前服务器在本机,所以InetAddress.getLocalHost().getHostAddress() //这个socket就是客户端的socket Socket socket = new Socket(InetAddress.getLocalHost().getHostAddress(),9999); //2.连接上后,获得输出流对象。该输出流对象是与该socket关联的 OutputStream outputStream = socket.getOutputStream(); //3.通过输出流对象,将数据写入数据通道 outputStream.write("hello,server".getBytes()); //4.必须关闭流对象和socket outputStream.close(); socket.close(); } }
- 细节:服务器端的ServerSocket每接收到一个连接请求,就会生成一个socket(服务器端的)
- 应用案例2演示(使用字节流)(1)编写一个服务器端和一个客户端(2)服务器端在9999端口监听(3)客户端连接到服务器端,发送“hello,server”,并接收服务器端回发的“hello,client”,再退出(4)服务器端接收到客户端发送的信息,输出,并向客户端发送“hello,client”,再退出
//服务器代码 package com.study.socket; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class SocketTCP02Server { public static void main(String[] args) throws IOException { //1.服务器端在9999端口监听 ServerSocket serverSocket = new ServerSocket(9999); //2.服务器端阻塞,等待客户端发来连接。服务器端接收到连接,才会生成自己的Socket对象 System.out.println("服务端在9999端口监听,等待连接..."); Socket socket = serverSocket.accept(); //客户端给服务端发 //3.服务器读取客户端在数据通道上写的数据,并显示 InputStream inputStream = socket.getInputStream(); //因为不是BufferedInputStream,所以要自己设置缓冲 byte[] b = new byte[1024]; int readLen = 0; while((readLen = inputStream.read(b)) != -1){ System.out.println(new String(b,0,readLen));//读多少数据写多少数据 } //服务端给客户端发 //4.服务器向客户端回发"hello,client"。先获得字节输出流,再将数据写入数据通道 OutputStream outputStream = socket.getOutputStream(); //因为是字节输出流,所以要将字符串转为字节数组输出 outputStream.write("hello,client".getBytes()); //设置写入结束标记!!! socket.shutdownOutput(); //5.关闭输入流输出流和两个socket inputStream.close(); outputStream.close(); socket.close(); //服务器要多关闭一个 serverSocket.close(); System.out.println("服务器退出..."); } }
//客户端代码 package com.study.socket; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; public class SocketTCP02Client { public static void main(String[] args) throws IOException { //1.客户端和服务器端建立连接 Socket socket = new Socket(InetAddress.getLocalHost().getHostAddress(),9999); //客户端给服务端发 //2.客户端向服务端发送"hello,server"。先获得字节输出流,再将数据写入数据通道 OutputStream outputStream = socket.getOutputStream(); //因为是字节输出流,所以要将字符串转为字节数组输出 outputStream.write("hello,server".getBytes()); //设置写入结束标记!!! socket.shutdownOutput(); //服务端给客户端发 //3.客户端读取服务器在数据通道上写的数据,并显示 InputStream inputStream = socket.getInputStream(); //因为不是BufferedInputStream,所以要自己设置缓冲 byte[] b = new byte[1024]; int readLen = 0; while((readLen = inputStream.read(b)) != -1){ System.out.println(new String(b, 0, readLen)); } //4.关闭输出流和输入流还有socket outputStream.close(); inputStream.close(); socket.close(); System.out.println("客户端退出"); } }
- 注意:服务器在输出客户端发来的“hello,server”后,不知道什么时候自己才能往数据通道数据,因此会阻塞。所以客户端在发完“hello,server”,服务器在发完“hello,client”后,都要设置结束标记,才能避免此类问题!这样,服务器就知道客户端已经写完了,自己可以写了。设置结束标记的方法:socket.shutdownOutput();
- 应用案例3(使用字符流)(1)编写一个服务端和一个客户端(2)服务端在9999端口监听(3)客户端连接到服务端,发送“hello,server”,并接收服务端回发的“hello,client”,再退出(4)服务端接收到客户端发送的信息,输出,并发送"hello,client",再退出
//服务器代码 package com.study.socket; import java.io.*; import java.net.ServerSocket; import java.net.Socket; public class SocketTCP03Server { public static void main(String[] args) throws IOException { //1.服务器在9999端口监听 ServerSocket serverSocket = new ServerSocket(9999); //2.服务端阻塞,等待客户端请求连接。一旦收到连接请求,就得到一个Socket对象 System.out.println("服务器在9999端口监听,等待连接..."); Socket socket = serverSocket.accept(); //客户端给服务器发 //3.服务器通过socket得到输入流,用输入流从数据通道读取数据 //因为题目要求用字符流处理问题,所以我们用到转换流和包装流 InputStream inputStream = socket.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); //由于客户端用writer.newLine()设置结束标记,所以我们只能用readLine读取数据 String line = bufferedReader.readLine(); System.out.println(line); //服务器给客户端发 OutputStream outputStream = socket.getOutputStream(); BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream)); bufferedWriter.write("hello,client"); bufferedWriter.newLine(); bufferedWriter.flush(); //关流 bufferedReader.close(); bufferedWriter.close(); socket.close(); serverSocket.close(); System.out.println("服务器退出..."); } }
//客户端代码 package com.study.socket; import java.io.*; import java.net.InetAddress; import java.net.Socket; public class SocketTCP03Client { public static void main(String[] args) throws IOException { //1.客户端向服务端建立连接(IP+端口) Socket socket = new Socket(InetAddress.getLocalHost().getHostAddress(),9999); //客户端给服务器发 //2.客户端通过socket得到输出流,用输出流向数据通道写入数据,写完了别忘记设置结束标记! //如果我们想用字符流处理问题,就要用到转换流将字节流转成字符流,还要用到包装流,将它包装为BufferedWriter OutputStream outputStream = socket.getOutputStream(); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream); BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter); //用该包装流写入数据 bufferedWriter.write("hello,server"); //结束标记socket.shutdownOutput();,或者如下 bufferedWriter.newLine(); //写完数据要刷新!!!这样才能真正写进去,这里不用关闭是因为关闭放在最后一部分!!! bufferedWriter.flush(); //服务器给客户端发 InputStream inputStream = socket.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String line = bufferedReader.readLine(); System.out.println(line); //关流 bufferedReader.close(); bufferedWriter.close(); socket.close(); System.out.println("客户端退出"); } }
- 使用字节流和使用字符流进行网络通信编程的区别:(1)使用字符流,需要先用socket得到字节流,再将字节流转换成字符流,最后将其包装成BufferedWriter/BufferedReader(2)字符流设置结束标记的方式:除了socket.shutdownOutput();,还有writer.newLine();。如果使用后者,那么对方必须用readLine读取数据(3)注意!!!一定要先newline,再flush
(3) 网络上传文件
- 应用案例演示4(1)编写一个服务端,和一个客户端(2)服务器端在8888端口监听(3)客户端连接到服务端,发送一张D盘下的图片(4)服务器端接收到客户端发送的图片,保存到src下,发送“收到图片”,再退出(5)客户端接收到服务端发送的“收到图片”,再退出
//服务器代码 package com.study.socket; import java.io.*; import java.net.ServerSocket; import java.net.Socket; public class SocketTCP04Server { public static void main(String[] args) throws IOException { //服务器在8888端口监听 ServerSocket serverSocket = new ServerSocket(8888); //等待客户端连接 System.out.println("服务器在8888端口监听,等待连接..."); Socket socket = serverSocket.accept(); //读取数据通道的dog.jpg,并将它写入src下 InputStream inputStream = socket.getInputStream(); String filePath = "src\\dog.jpg"; BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(filePath)); //建立缓冲 byte[] b = new byte[1024]; int readLen = 0; while((readLen=inputStream.read(b))!=-1){ bufferedOutputStream.write(b,0,readLen); } //服务器向客户端发送"收到图片" OutputStream outputStream = socket.getOutputStream(); BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream)); bufferedWriter.write("收到图片"); bufferedWriter.newLine(); bufferedWriter.flush(); //退出 inputStream.close(); bufferedOutputStream.close(); bufferedWriter.close(); socket.close(); serverSocket.close(); System.out.println("服务器退出..."); } }
//客户端代码 package com.study.socket; import java.io.*; import java.net.InetAddress; import java.net.Socket; @SuppressWarnings("ALL") public class SocketTCP04Client { public static void main(String[] args) throws IOException { //与服务端建立连接 Socket socket = new Socket(InetAddress.getLocalHost().getHostAddress(),8888); //将D盘下的dog.jpg写入数据通道 String filePath = "D:\\dog.jpg"; BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath)); OutputStream outputStream = socket.getOutputStream(); //建立缓冲 byte[] b = new byte[1024]; int readLen = 0; //相当于读到客户端 while((readLen=bufferedInputStream.read(b))!=-1){ outputStream.write(b,0,readLen);//读多少写多少 } //设置结束标记 socket.shutdownOutput(); //客户端接收到服务端发送的“收到图片” InputStream inputStream = socket.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String line = bufferedReader.readLine(); System.out.println(line); //退出 bufferedInputStream.close(); outputStream.close(); bufferedReader.close(); socket.close(); System.out.println("客户端退出..."); } }
- 总结:(1)如果与数据通道相关,从数据通道读取数据InputStream inputStream = socket.getInputStream();,向数据通道写入数据OutputStream outputStream = socket.getOutputStream();(2)在此基础上,如果我们需要使用字符流来操作,那么我们就用转换流和包装流(3)与数据通道无关的,我们可以参考IO流
(4)netstat指令
- netstat -an 可以查看当前主机网络情况,包括端口监听情况和网络连接情况
- Listening表示某个端口在监听
- 如果有一个外部程序(客户端)连接到该端口,就会显示一条连接信息(Established)
- Ctrl+C可以退出该指令
- netstat -an|more可以分页显示,翻页:在光标闪烁处输入空格键
- 要求在dos控制台下执行
- 如果想知道是哪个程序在监听此端口,那么(要以管理员身份运行):netstat -anb
- 如果是上面应用案例演示的代码,那么8888端口就是被java.exe监听
(5) TCP连接秘密
- 当客户端连接到服务端后,实际上客户端也是通过一个端口和服务端进行通讯的,这个客户端的端口是随机的,是TCP/IP来分配的
- 当TCP连接被释放后,客户端的端口就会被释放
五、UDP编程
(1)UDP网络通信编程基本介绍
- 类DatagramSocket和类DatagramPacket实现了基于UDP协议的网络通信
- UDP数据报通过数据报套接字DatagramSocket发送和接收,系统不保证UDP数据报一定能安全送到目的地,也不能确定什么时候可以抵达
- DatagramPacket对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号,以及接收端的IP地址和端口号
- UDP协议中每个数据报都给出了完整的地址信息,因此无需建立发送方和接收方的连接
(2)UDP网络通信编程
- 基本流程:
- 核心的两个类/对象:DatagramSocket(接收端指定在哪个端口接收数据/发送端指定在哪个端口发送数据),DatagramPacket(接收端需要创建,用来接收发送端发来的DatagramPacket对象;发送端也需要创建,把需要发送的数据放进DatagramPacket对象)
- 建立发送端、接收端,二者可以随时转换,即发送端当接收来自接收端的数据时,它又可以成为接收端(没有服务端和客户端概念)
- 发送数据前,建立数据报 DatagramPacket对象
- 调用DatagramSocket的发送、接收方法(socket.receive(接收端创建的DatagramPacket对象),socket.send(发送端创建的DatagramPacket对象))
- 关闭DatagramSocket
- UDP说明:
- 没有明确的服务端和客户端,演变成发送端和接收端
- 接收数据和发送数据是通过DatagramSocket对象完成
- 将数据封装到DatagramPacket对象(装包),发送
- 当接收到在网络上传送的DatagramPacket对象时,需要进行拆包,取出数据
- DatagramSocket指定在哪个端口接收数据
- 应用案例演示(1)编写一个接收端A,和一个发送端B(2)接收端A在9999端口等待接收数据(3)发送端B向接收端A发送数据“hello,明天吃火锅~”(4)接收端A接收到发送端B发送的数据,回复“好的,明天见”,再退出(5)发送端B接收到回复的数据,再退出
//接收端A的代码 package com.study.UDP; import java.io.IOException; import java.net.*; public class UDPReceiverA { public static void main(String[] args) throws IOException { //1.创建一个DatagramSocket对象,准备在9999端口接收数据 DatagramSocket socket = new DatagramSocket(9999); //2.构建一个DatagramPacket对象,准备接收数据 //UDP协议中,每个数据报最大是64K byte[] b = new byte[1024]; DatagramPacket packet = new DatagramPacket(b, b.length); //3.调用接收方法。将通过网络传输的DatagramPacket对象,填充到这里的packet对象 //如果没有数据发送到9999端口,就会阻塞等待 System.out.println("接收端A等待接收数据..."); socket.receive(packet); //4.把packet进行拆包,取出数据并显示 int length = packet.getLength();//实际接收到的数据字节长度 byte[] data = packet.getData();//实际接收到的数据 System.out.println(new String(b, 0, length)); //5.接收端A向发送端B回复信息"好的,明天见" byte[] info = "好的,明天见".getBytes(); DatagramPacket packet2 = new DatagramPacket(info,info.length, InetAddress.getLocalHost(),9998); socket.send(packet2); //6.关闭资源socket socket.close(); System.out.println("A端退出"); } }
package com.study.UDP; import java.io.IOException; import java.net.*; public class UDPSenderB { public static void main(String[] args) throws IOException { //1.创建DatagramSocket对象,准备在9998发送数据 DatagramSocket socket = new DatagramSocket(9998); //2.将需要发送的数据封装到DatagramPacket(数据,数据的长度,接收端ip,接收端端口) byte[] info = "hello,明天吃火锅~".getBytes(); DatagramPacket packet = new DatagramPacket(info, info.length, InetAddress.getLocalHost(),9999); //3.发送DatagramPacket对象 socket.send(packet); //4.发送端接收接收端回复的信息"好的,明天见" byte[] b = new byte[1024]; DatagramPacket packet2 = new DatagramPacket(b,b.length); System.out.println("发送端B等待接收数据..."); socket.receive(packet2); int length = packet2.getLength(); byte[] data = packet2.getData(); System.out.println(new String(data, 0, length)); //关闭资源 socket.close(); System.out.println("B端退出"); } }
- 此时使用netstat -an命令,可以看到UDP的9999端口正在监听
- 总结:
//发送端发送数据的核心代码 //第一步,设置在哪个端口发送数据(该端口还可以用来接收数据) DatagramSocket socket = new DatagramSocket(9998); //第二步,将需要发送的数据转成字节数据,放入DatagramPacket对象,并指定要发给哪个ip、端口 byte[] info = "hello,明天吃火锅~".getBytes(); DatagramPacket packet = new DatagramPacket(info, info.length, InetAddress.getLocalHost(),9999); //第三步,发送DatagramPacket对象 socket.send(packet);
//接收端接收数据的核心代码 //第一步,创建一个合理大小的DatagramPacket对象(数据都是以字节数组的形式保存的) byte[] b = new byte[1024]; DatagramPacket packet = new DatagramPacket(b, b.length); //第二步,接收来自发送端的DatagramPacket对象,并将该对象转成自己创建的DatagramPacket对象 socket.receive(packet); //第三步,如果我们需要在屏幕上显示数据 int length = packet.getLength();//实际接收到的数据字节长度 byte[] data = packet.getData();//实际接收到的数据 System.out.println(new String(b, 0, length));
六、网络编程作业
- 编程题1(1)使用字符流的方式,编写一个客户端程序和一个服务器端程序(2)客户端发送“name”,服务器端接收到后,返回“我是nova”,nova是你自己的名字(3)客户端发送“hobby”,服务器端接收到后,返回“编写Java程序”(4)不是这两个问题,回复“你说啥呢”
//服务器端代码 package com.study.homework; import java.io.*; import java.net.*; @SuppressWarnings("ALL") public class Server_ { public static void main(String[] args) throws IOException { //1.在本机的9999端口监听,等待连接 ServerSocket serverSocket = new ServerSocket(9999); //2.阻塞等待客户端的连接 System.out.println("服务器端等待连接..."); Socket socket = serverSocket.accept(); //3.服务端接收用户发来的问题,注意题目要求使用字符流 InputStream inputStream = socket.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); //4.因为客户端使用newLine设置结束标记的,因此我们要用readLine读数据 String line = bufferedReader.readLine(); String info = "";//要发送给客户端的数据 //5.根据用户发的问题确定要返回什么信息 if ("name".equals(line)){ info = "Tom"; }else if ("hobby".equals(line)){ info = "编写Java程序"; }else{ info = "你说啥呢"; } //6.将要返回给客户端的数据写进数据通道 OutputStream outputStream = socket.getOutputStream(); BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream)); bufferedWriter.write(info); //7.设置结束标记并刷新 bufferedWriter.newLine(); bufferedWriter.flush(); //6.关流,关闭资源 bufferedWriter.close(); bufferedReader.close(); socket.close(); serverSocket.close(); System.out.println("服务器端退出..."); } }
//客户端代码 package com.study.homework; import java.io.*; import java.net.*; import java.util.Scanner; @SuppressWarnings("ALL") public class Client_ { public static void main(String[] args) throws IOException { //1.向服务器端发起连接 Socket socket = new Socket(InetAddress.getLocalHost(),9999); //2.接收用户从键盘输入的数据 Scanner scanner = new Scanner(System.in); System.out.print("请输入你的问题:"); String next = scanner.next(); //3.向服务器端发送用户输入的问题,注意题目要求使用字符流 OutputStream outputStream = socket.getOutputStream(); BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream)); bufferedWriter.write(next); //4.注意:要设置结束标记!还要刷新输出流,才能将数据真正写进数据通道 bufferedWriter.newLine(); bufferedWriter.flush(); //5.客户端接收来自服务器端的问题回答 InputStream inputStream = socket.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String info = bufferedReader.readLine(); System.out.println(info); //6.关流,关闭资源 bufferedWriter.close(); bufferedReader.close(); socket.close(); System.out.println("客户端退出..."); } }
- 编程题2(1)编写一个接收端A,和一个发送端B,使用UDP协议完成(2)接收端在8888端口等待接收数据(3)发送端向接收端发送数据“四大名著是哪些”(4)接收端接收到发送端发送的问题后,返回“四大名著是《红楼梦》...”,否则返回what?(5)接收端和发送端程序退出
//接收端代码 package com.study.homework; import java.io.IOException; import java.net.*; @SuppressWarnings("ALL") public class Receiver_ { public static void main(String[] args) throws IOException { //1.接收端在8888端口等待接收数据 DatagramSocket socket = new DatagramSocket(8888); //2.创建一个DatagramPacket对象,用来接收发送端发来的数据,大小暂定为1024 byte[] b = new byte[1024]; DatagramPacket packet = new DatagramPacket(b,b.length); System.out.println("接收端等待接收问题..."); //3.接收发送端发来的问题 socket.receive(packet); //4.根据问题内容判断要回复的信息 String info = ""; int length = packet.getLength(); byte[] data = packet.getData(); String line = new String(data,0,length); if ("四大名著是哪些".equals(line)){ info = "四大名著是《红楼梦》《三国演义》《水浒传》《西游记》"; }else{ info = "what?"; } //5.将要回复的信息放在DatagramPacket对象,并发送给发送端 byte[] answer = info.getBytes(); DatagramPacket packet2 = new DatagramPacket(answer,answer.length,InetAddress.getLocalHost(),9999); socket.send(packet2); //6.关闭资源 socket.close(); System.out.println("接收端退出..."); } }
//发送端代码 package com.study.homework; import java.io.IOException; import java.net.*; import java.util.Scanner; @SuppressWarnings("ALL") public class Sender_ { public static void main(String[] args) throws IOException { //1.发送端在9999端口发送数据 DatagramSocket socket = new DatagramSocket(9999); //2.创建一个扫描器对象,等用户从键盘输入问题 Scanner scanner = new Scanner(System.in); System.out.print("请输入你的问题:"); String next = scanner.next(); //3.将用户输入的问题放入DatagramPacket对象 byte[] question = next.getBytes(); DatagramPacket packet = new DatagramPacket(question,question.length,InetAddress.getLocalHost(),8888); //4.将DatagramPacket对象发送给接收端 socket.send(packet); //5.接收接收端发送来的答案,并在屏幕输出 byte[] b = new byte[1024]; DatagramPacket packet2 = new DatagramPacket(b,b.length); socket.receive(packet2); int length = packet2.getLength(); byte[] data = packet2.getData(); System.out.println(new String(data, 0, length)); //6.关闭资源 socket.close(); System.out.println("发送端退出..."); } }
- TCP文件下载(1)编写客户端程序和服务器端程序(2)客户端可以输入一个图片文件名,比如dog,服务端收到图片名后,可以给客户端返回这个图片文件,如果服务器没有这个文件,返回默认的cat.jpg即可(3)客户端收到该文件后,保存到D:\demo02\dog.jpg(文件名指定是这个)
//服务器端代码 package com.study.homework02; import java.io.*; import java.net.*; @SuppressWarnings("ALL") public class Server { public static void main(String[] args) throws IOException { //1.服务器端在9999端口监听,等待客户端的连接 ServerSocket serverSocket = new ServerSocket(9999); //2.服务器等待来自客户端的连接 System.out.println("服务器等待来自客户端的连接..."); Socket socket = serverSocket.accept(); //3.从数据通道读取客户端发来的信息 InputStream inputStream = socket.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); //因为客户端使用newLine来设置结束标记,因此我们用readLine读数据 String fileName = bufferedReader.readLine(); //4.根据用户输入的文件名,判断我们要从磁盘中读取哪个文件并写入数据通道 String srcFilePath = ""; if("dog".equals(fileName)){ srcFilePath = "D:\\dog.jpg"; }else{ srcFilePath = "D:\\cat.jpg"; } //5.从磁盘读取文件(输入流)并写入数据通道(输出流) BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(srcFilePath)); OutputStream outputStream = socket.getOutputStream();//使用的是字节流,因此不需要转换和包装 //字节流要设置缓冲 byte[] b = new byte[1024]; int readLen = 0; while((readLen = bufferedInputStream.read(b))!=-1){//已经读到末尾会返回-1 outputStream.write(b,0,readLen);//读多少,写多少。用数组缓冲都要涉及这个 } //6.TCP往数据通道写完数据,一定要设置结束标记 socket.shutdownOutput(); //7.关流关资源 bufferedReader.close(); outputStream.close(); bufferedInputStream.close(); socket.close(); serverSocket.close(); System.out.println("服务器端退出"); } }
//客户端代码 package com.study.homework02; import java.io.*; import java.net.*; import java.util.Scanner; @SuppressWarnings("ALL") public class Client { public static void main(String[] args) throws IOException { //1.客户端向服务端发起请求连接 Socket socket = new Socket(InetAddress.getLocalHost(),9999); //2.接收用户从键盘输入的信息 Scanner scanner = new Scanner(System.in); System.out.print("请输入要下载的图片名:"); String next = scanner.next(); //3.将用户输入的信息写进数据通道 OutputStream outputStream = socket.getOutputStream(); BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream)); bufferedWriter.write(next); //4.设置结束标记,并刷新 bufferedWriter.newLine(); bufferedWriter.flush(); //5.从数据通道读取文件并将它写入目标位置 String destFilePath = "D:\\demo02\\dog.jpg"; InputStream inputStream = socket.getInputStream();//字节流,因此不需要转换和包装 BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(destFilePath));//包装流就是对节点流进行包装 //设置缓冲 byte[] b = new byte[1024]; int readLen = 0; while((readLen = inputStream.read(b))!=-1){ bufferedOutputStream.write(b,0,readLen); } //6.关流关资源 bufferedWriter.close(); inputStream.close(); bufferedOutputStream.close(); socket.close(); System.out.println("下载成功!"); System.out.println("客户端退出..."); } }
本笔记根据韩顺平零基础学Java课程学习整理而来
标签:Java,socket,java,编程,网络,import,close,new,客户端 From: https://blog.csdn.net/weixin_74019079/article/details/144185872