Java——TCP UDP Socket编程 基础网络知识,Java——TCP UDP Socket编程

目录

一、网络的相关概念

(一)网络通信

(二)网络

(三)ip地址

(四)ipv4地址分类

(五)域名

(六)网络通信协议

(七)TCP和UDP

二、InetAddress类

三、Socket

四、TCP网络编程

(一)案例一——使用字节流

(二)案例二——使用字节流 

(三)案例三——使用字符流

(四)案例四——使用字符流

五、UDP网络编程

(一)基本介绍

(二)基本流程

(三)案例

六、案例

(一)案例一

(二)案例二


一、网络的相关概念

(一)网络通信

1.概念:两台设备之间通过网络实现数据传输

2.网络通信:将数据通过网络从一台设备传输到另一台设备

3.java.net包下提供了一系列的类或接口,供程序员使用,完成网络通信

(二)网络

1.概念:两台或多台设备通过一定物理设备连接起来构成了网络
2.根据网络的覆盖范围不同,对网络进行分类:

  • 局域网: 覆盖范围最小,仅仅覆盖一个教室或一个机房
  • 城域网:覆盖范围较大,可以覆盖一个城市
  • 广域网:覆盖范围最大,可以覆盖全国,甚至全球,万维网是广域网的代表

(三)ip地址

1.概念: 用于唯一标识网络中的每台计算机/主机

2.查看ip地址: ipconfig

3.ip地址的表示形式:点分十进制 xx.xx.xx.xx

4.每一个十进制数的范围: 0~255
5.ip地址的组成=网络地址+主机地址,比如: 192.168.16.69

6.lPv6是互联网工程任务组设计的用于替代IPv4的下一代IP协议,其地址数量号称可以为全世界的每一粒沙子编上一个地址

7.由于IPv4最大的问题在于网络地址资源有限,严重制约了互联网的应用和发展。IPv6的使用,不仅能解决网络地址资源数量的问题,而且也解决了多种接入设备连入互联网的障碍

(四)ipv4地址分类

(五)域名

1.比如www.baidu.com,将ip映射到域名上,访问域名就是访问ip
2.好处:为了方便记忆,解决记ip的困难


端口号

1.概念: 用于标识计算机上某个特定的网络程序

2.表示形式: 以整数形式,端口范围0~65535 [2个字节表示端口 0~2^16-1]

3.0~1024已经被占用, 比如 ssh 22, ftp 21, smtp 25 http 80

4.常见的网络程序端口号:

  • tomcat :8080
  • mysql:3306
  • oracle:1521
  • sqlserver:1433

(六)网络通信协议

协议(tcp/ip)

TCP/IP (Transmission Control Protocol/Internet Protocol)的简写, 中文译名为传输控制协议/因特网互联协议,又叫网络通讯协议,这个协议是Internet最基本的协议、Internet国际互联网络的基础,简单地说,就是由网络层的IP协议和传输层的TCP协议组成的

(七)TCP和UDP

TCP协议: 传输控制协议
1.使用TCP协议前,须先建立TCP连接,形成传输数据通道

2.传输前,采用“三次握手"方式,是可靠的

3.TCP协议进行通信的两个应用进程: 客户端、服务端

4.在连接中可进行大数据量的传输

5.传输完毕,需释放已建立的连接,效率低

UDP协议: 用户数据协议
1.将数据、源、目的封装成数据包,不需要建立连接

2.每个数据报的大小限制在64K内,不适合传输大量数据

3.因无需连接,故是不可靠

4.发送数据结束时无需释放资源(因为不是面向连接的),速度快

5.举例: 发短信

二、InetAddress类

方法:

  1. 获取本机InetAddress对象 getLocalHost
  2. 根据指定主机名/域名获取ip地址对象 getByName
  3. 获取InetAddress对象的主机名 getHostName
  4. 获取InetAddress对象的地址 getHostAddress
/*
 * 演示InetAddress类的使用
 */
public class API_ {
 public static void main(String[] args) throws UnknownHostException {
 // 1.获取本机的InetAddress对象
 InetAddress localHost = InetAddress.getLocalHost();
 System.out.println(localHost); // LAPTOP-RVFFB7FM/192.168.23.1
 // 2.根据机器的名字获取InetAddress对象
 InetAddress inetAddress = InetAddress.getByName("LAPTOP-RVFFB7FM");
 System.out.println(inetAddress);
 // 3.根据域名返回InetAddress对象,比如www.baidu.com
 InetAddress inetAddress1 = InetAddress.getByName("www.baidu.com");
 System.out.println(inetAddress1);
 // 4.根据InetAddress对象,获取对应的ip地址
 String address = inetAddress1.getHostAddress();
 System.out.println(address);
 // 5.通过InetAddress对象,获取对应的主机名
 String hostName = inetAddress1.getHostName();
 System.out.println(hostName);
 }
}

三、Socket

1.套接字(Socket)开发网络应用程序被广泛采用,以至于成为事实上的标准

2.通信的两端都要有Socket,是两台机器间通信的端点,网络通信其实就是Socket间的通信

3.Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输

4.一般主动发起通信的应用程序属客户端,等待通信请求的为服务端

四、TCP网络编程

1.基于客户端一服务端的网络通信, 底层使用的是TCP/IP协议

2.应用场景举例: 客户端发送数据,服务端接受并显示控制台

3.基于Socket的TCP编程

(一)案例一——使用字节流

 

服务端

public class SocketTCP01Server {
 public static void main(String[] args) throws IOException {
 // 1.在9999端口监听,等待链接
 // 细节:要求该端口没有其他人监听
 ServerSocket serverSocket = new ServerSocket(9999);
 System.out.println("服务端,在9999端口监听,等待连接...");
 // 2.如果没有客户端连接9999端口,该方法会阻塞等待连接
 // 如果有连接,返回一个socket
 Socket socket = serverSocket.accept();
 System.out.println(socket.getClass());
 // 3.通过socket.getInputStream() 读取
 // 客户端写入到数据通道的数据,显示
 InputStream inputStream = socket.getInputStream();
 byte[] bytes = new byte[1024];
 int readLen = 0;
 while((readLen = inputStream.read(bytes)) != -1) {
 System.out.println(new String(bytes, 0, readLen));
 }
 // 4.关闭流
 inputStream.close();
 socket.close();
 serverSocket.close();
 System.out.println("服务端退出...");
 }
}

客户端 

public class SocketTCP01Client {
 public static void main(String[] args) throws IOException {
 // 1.连接9999端口,连接成功返回一个socket
 Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
 // 2.连接上后,生成socket,通过socket.getOutputStream()
 OutputStream outputStream = socket.getOutputStream();
 // 3.输出信息
 outputStream.write("hello, socket".getBytes());
 // 4.关闭流和连接,节省资源
 outputStream.close();
 socket.close();
 System.out.println("客户端退出...");
 }
}

(二)案例二——使用字节流 

服务端

public class SocketTCP02Server {
 public static void main(String[] args) throws Exception {
 ServerSocket serverSocket = new ServerSocket(9999);
 Socket socket = serverSocket.accept();
 InputStream inputStream = socket.getInputStream();
 byte[] buf = new byte[1024];
 int readLen = 0;
 while((readLen = inputStream.read(buf)) != -1) {
 System.out.println(new String(buf, 0, readLen));
 }
 OutputStream outputStream = socket.getOutputStream();
 outputStream.write("hello Client".getBytes());
 // 设置结束标记
 socket.shutdownOutput();
 outputStream.close();
 inputStream.close();
 socket.close();
 serverSocket.close();
 }
}

客户端 

public class SocketTCP02Client {
 public static void main(String[] args) throws Exception{
 Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
 OutputStream outputStream = socket.getOutputStream();
 outputStream.write("hello Server".getBytes());
 // 设置结束标记, socket.close()也做了同样的事情
 // 但是因为我们下面还有获取数据通道信息,因此不能关闭,只能shutdownOutput()
 socket.shutdownOutput();
 InputStream inputStream = socket.getInputStream();
 byte[] buf = new byte[1024];
 int readLen = 0;
 while((readLen = inputStream.read(buf)) != -1) {
 System.out.println(new String(buf, 0, readLen));
 }
 outputStream.close();
 inputStream.close();
 socket.close();
 }
}

(三)案例三——使用字符流

服务端

public class SocketTCP03Server {
 public static void main(String[] args) throws Exception {
 ServerSocket serverSocket = new ServerSocket(9999);
 Socket socket = serverSocket.accept();
 InputStream inputStream = socket.getInputStream();
 // IO读取,使用字符流输入,使用InputStreamReader将InputStream转化为字符流
 BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
 String s = reader.readLine();
 System.out.println(s);
 // 字符流方式的输出
 OutputStream outputStream = socket.getOutputStream();
 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
 writer.write("hello Client 字符流");
 writer.newLine(); // 插入一个换行符,代表写入的内容结束
 writer.flush(); // 字符流需要手动刷新,否则数据不会写入数据通道
 reader.close();
 writer.close();
 socket.close();
 serverSocket.close();
 }
}

客户端 

public class SocketTCP03Client {
 public static void main(String[] args) throws Exception{
 Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
 OutputStream outputStream = socket.getOutputStream();
 // 通过输出流,转换为字符流
 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
 writer.write("hello Server 字符流");
 writer.newLine(); // 插入一个换行符,代表写入的内容结束
 writer.flush(); // 字符流需要手动刷新,否则数据不会写入数据通道
 InputStream inputStream = socket.getInputStream();
 BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
 String s = reader.readLine();
 System.out.println(s);
 reader.close();
 writer.close();
 socket.close();
 System.out.println("客户端退出...");
 }
}

(四)案例四——使用字符流

 StreamUtils

/**
 * 此类用于演示关于流的读写方法
 *
 */
public class StreamUtils {
	/**
	 * 功能:将输入流转换成byte[], 即可以把文件的内容读入到byte[]
	 * @param is
	 * @return
	 * @throws Exception
	 */
	public static byte[] streamToByteArray(InputStream is) throws Exception{
	ByteArrayOutputStream bos = new ByteArrayOutputStream();//创建输出流对象
	byte[] b = new byte[1024];//字节数组
	int len;
	while((len=is.read(b))!=-1){//循环读取
	bos.write(b, 0, len);//把读取到的数据,写入bos	
	}
	byte[] array = bos.toByteArray();//然后将bos 转成字节数组
	bos.close();
	return array;
	}
	/**
	 * 功能:将InputStream转换成String
	 * @param is
	 * @return
	 * @throws Exception
	 */
	
	public static String streamToString(InputStream is) throws Exception{
	BufferedReader reader = new BufferedReader(new InputStreamReader(is));
	StringBuilder builder= new StringBuilder();
	String line;
	while((line=reader.readLine ())!=null){
	builder.append(line+"\r\n");
	}
	return builder.toString();
	
	}
}

服务端

public class TCPFileUploadServer {
 public static void main(String[] args) throws Exception {
 ServerSocket serverSocket = new ServerSocket(8888);
 // 等待连接
 Socket socket = serverSocket.accept();
 InputStream inputStream = socket.getInputStream();
 BufferedInputStream bis = new BufferedInputStream(inputStream);
 byte[] bytes = StreamUtils.streamToByteArray(bis);
 String destFilePath = "src\\a.jpg";
 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
 bos.write(bytes);
 bos.close();
 // 向客户端回复“收到图片”
 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
 writer.write("收到图片");
 writer.flush();
 writer.close();
 bis.close();
 socket.close();
 }
}

客户端 

public class TCPFileUploadClient {
 public static void main(String[] args) throws Exception{
 // 客户端连接服务端8888端口,得到socket对象
 Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
 // 读取本地的文件转换为字节数组
 String filePath = "D:\\image\\a.jpg";
 FileInputStream fileInputStream = new FileInputStream(filePath);
 BufferedInputStream bis = new BufferedInputStream(fileInputStream);
 // 该字节数组就是文件
 byte[] bytes = StreamUtils.streamToByteArray(bis);
 OutputStream outputStream = socket.getOutputStream();
// outputStream.write(bytes);
 BufferedOutputStream bos = new BufferedOutputStream(outputStream);
 bos.write(bytes);
 
 socket.shutdownOutput(); // 写入数据的结束标记
 BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
 String s = reader.readLine();
 System.out.println(s);
 reader.close();
 bos.close();
 bis.close();
 socket.close();
 }
}

五、UDP网络编程

(一)基本介绍

1.类 DatagramSocket DatagramPacket[数据包/数据报]实现了基于 UDP协议网络程序。

2.UDP数据报通过数据报套接字 DatagramSocket 发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。

3.DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。

4.UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接

(二)基本流程

1.核心的两个类/对象 DatagramSocket与DatagramPacket

2.建立发送端,接收端(没有服务端和客户端概念)

3.发送数据前,建立数据包/报 DatagramPacket对象

4.调用DatagramSocket的发送、接收方法

5.关闭DatagramSocket

(三)案例

发送端

public class UDPSenderB {
 public static void main(String[] args) throws Exception{
 // 1.创建一个DatagramSocket,监听9998端口
 DatagramSocket socket = new DatagramSocket(9998);
 // 2.创建DatagramPacket,接收数据
 byte[] data = "你好,明天吃火锅".getBytes();
 DatagramPacket packet = new DatagramPacket(data, 0, data.length, InetAddress.getByName("192.168.23.1"), 9999);
 // 3.发送数据
 socket.send(packet);
 // 接收消息
 data = new byte[1024];
 packet = new DatagramPacket(data, data.length);
 socket.receive(packet);
 int length = packet.getLength();
 data = packet.getData();
 String msg = new String(data, 0, length);
 System.out.println(msg);
 // 4.关闭资源
 socket.close();
 }
}

接收端

public class UDPReceiverA {
 public static void main(String[] args) throws Exception{
 // 1.创建一个DatagramSocket对象,监听9999端口
 DatagramSocket socket = new DatagramSocket(9999);
 // 2.构建一个DatagramPacket,准备接受数据
 byte[] data = new byte[1024];
 DatagramPacket packet = new DatagramPacket(data, data.length);
 // 3.接收数据,如果没有数据则堵塞,接收到的数据存放在packet中
 System.out.println("接收端A等待接收数据...");
 socket.receive(packet);
 // 4.接收完数据转化为String并输出
 int length = packet.getLength();
 data = packet.getData();
 String msg = new String(data, 0, length);
 System.out.println(msg);
 // 回复消息
 data = "好的,明天见".getBytes();
 packet = new DatagramPacket(data, 0, data.length, InetAddress.getByName("192.168.23.1"), 9998);
 socket.send(packet);
 // 5.关闭资源
 socket.close();
 }
}

六、案例

(一)案例一

服务端

public class HomeWork01Server {
 public static void main(String[] args) throws Exception{
 System.out.println("服务器等待接收消息...");
 DatagramSocket socket = new DatagramSocket(9999);
 byte[] data = new byte[1024];
 DatagramPacket packet = new DatagramPacket(data, data.length);
 socket.receive(packet);
 int length = packet.getLength();
 data = packet.getData();
 String msg = new String(data, 0, length);
 System.out.println(msg);
 String returnMsg = "";
 if("name".equals(msg)) {
 returnMsg = "我是nova";
 } else if("hobby".equals(msg)){
 returnMsg = "编写java程序";
 } else {
 returnMsg = "你说啥呢";
 }
 data = returnMsg.getBytes();
 packet = new DatagramPacket(data, 0, data.length, InetAddress.getByName("192.168.23.1"), 9998);
 socket.send(packet);
 socket.close();
 }
}

客户端

public class HomeWork01Client {
 public static void main(String[] args) throws Exception{
 System.out.println("请输入您的消息:");
 Scanner sc = new Scanner(System.in);
 String msg = sc.next();
 DatagramSocket socket = new DatagramSocket(9998);
 byte[] data = msg.getBytes();
 DatagramPacket packet = new DatagramPacket(data, 0, data.length, InetAddress.getByName("192.168.23.1"), 9999);
 socket.send(packet);
 data = new byte[1024];
 packet = new DatagramPacket(data, data.length);
 socket.receive(packet);
 int length = packet.getLength();
 data = packet.getData();
 System.out.println(new String(data, 0, length));
 }
}

(二)案例二

服务端

public class HomeWork03Server {
 public static void main(String[] args) throws Exception{
 System.out.println("服务端监听9999端口,等待接收文件名...");
 // 1.创建一个socket对象
 ServerSocket serverSocket = new ServerSocket(9999);
 // 2.接收传递过来的文件名
 Socket socket = serverSocket.accept();
 InputStream inputStream = socket.getInputStream();
 // 这里使用了while循环,是考虑客户端可能发送的文件名较大的情况
 byte[] buf = new byte[1024];
 int len = 0;
 String downLoadFileName = "";
 while((len = inputStream.read(buf)) != -1) {
 downLoadFileName += new String(buf, 0, len);
 }
 System.out.println("客户端希望下载的文件名: " + downLoadFileName);
 // 3.确定文件名
 // 如果客户端要求下载高山流水,则获取文件流返回,否则,返回无名mp3
 String filePath = "";
 if("高山流水".equals(downLoadFileName)) {
 filePath = "src//高山流水.mp3";
 } else {
 filePath = "src//无名.mp3";
 }
 // 4.获取文件输入流并转化为字节数组
 BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
 byte[] data = StreamUtils.streamToByteArray(bis);
 // 5.获取socket输出流并写出数据
 BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
 bos.write(data);
 socket.shutdownOutput();
 // 6.关闭资源
 bos.close();
 bis.close();
 socket.close();
 serverSocket.close();
 System.out.println("服务端传输文件完毕,退出");
 }
}

客户端

public class HomeWork03Client {
 public static void main(String[] args) throws Exception{
 System.out.println("请输入下载的文件名:");
 // 1.获取用户输入的文件名
 Scanner sc = new Scanner(System.in);
 String fileName = sc.next();
 // 2.创建连接
 Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
 // 3.获取socket关联的输出流并写出
 OutputStream outputStream = socket.getOutputStream();
 outputStream.write(fileName.getBytes());
 // 设置写入结束的标记
 socket.shutdownOutput();
 // 4.获取输入流并转化为字节数组
 BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
 byte[] data = StreamUtils.streamToByteArray(bis);
 // 5.获取写出流,将文件写入磁盘
 String fileNamePath = "src//com//hspedu/homework//" + fileName + ".mp3";
 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(fileNamePath));
 bos.write(data);
 // 6.关闭资源
 outputStream.close();
 bos.close();
 bis.close();
 socket.close();
 System.out.println("文件下载完毕,退出");
 }
}

作者:zoeil原文地址:https://blog.csdn.net/m0_62946761/article/details/130795291

%s 个评论

要回复文章请先登录注册