一、相关概念
- 网络通信:两台设备通过网络进行数据传输;
- 网络:多台设备通过物理设备连接成网络;
- ip地址:计算机的唯一标识,由网络地址和主机地址组成,占4个字节32位;
- 域名:ip地址的映射,ip地址相当于身份证号,域名就是名字,都是唯一表示,只是为了方便记忆;
- 端口:计算机上特定的网络程序(特定功能);ip地址是家,端口就是不同的房间,进厨房是做饭,进客厅是看电视,进卧室是睡觉;
- 网络协议:举个例子,人与人之间的交流,是文字(相当于程序的数据)以一定的形式组织起来(即语言)进行交流,文字的组织形式即语言,就是协议。程序与程序之间的交流,是数据以一定的形式组织起来进行传输(交流),数据的组织形式就是协议;
- TCP协议:传输控制协议,相当于打电话,三个特点:
1.通过“三次握手”的方式建立数据传输通道,可靠;
2.可传输大量数据;
3.需要释放连接,效率低;
- UDP协议:用户数据协议,相当于发信息,三个特点:
1.将数据封装成数据包,无需连接,不可靠;
2.数据包在64k以内,不能传输大量数据;
3.无需释放连接,效率高(速度快);
二、InetAddress类
1.是什么?
是一个用来获取主机ip地址和主机名的类;
2.怎么用?
四个方法:InetAddress对象就是主机名+ip地址
三、Socket端点
(1).是什么?
是两台机器(服务端 客服端)之间用来通讯(读写数据)的插头,网络通讯就是把网络当成一个流,在两个Socket之间进行通讯,即数据在两个Socket之间用IO流传输(InputStream和OutputStream),网络通讯其实就是两个Socket之间的通讯;举个例子:Socket就像是两个邻居房间的大门
什么是服务端、客户端?发起通讯请求的是客户端,接收通讯请求的是服务端;
(2).有什么用?
实现客户端和服务端之间的通讯(UDP是实现接收端和发送端之间的通讯);
(3).怎么用?
Socket编程有两种方式,一种是TCP编程(可靠),另一种是UDP编程(不可靠),又分别分为字节流和字符流
第一种:TCP编程
数据读取:调用socket.getInputStream()来获得输入流对象来读取数据,调用socket.getOutputStream()来获得输出流对象来写入数据;可以使用包装流,也可以根据实际情况使用转换流将字节流转换成字符流;
具体过程:演示客户端连接服务端,客户端写入数据到数据通道,服务端从数据通道读取数据;
服务端:创建SocketSocket对象,传入端口,然后调用SocketSocket对象的accept()方法判断是否于客户端连接,如果连接了,就返回一个socket接口,用来获取一个IO流对象,用IO流对象来调用读写数据的方法,最后关闭IO流和socket(服务端的ServeSocket也要关闭)
客户端:和服务端差不多,创建一个Socket对象,用InetAddress.getLocalHost()方法传入IP地址和需要连接的端口,连接后生成Socket,通过Socket.getInputStream(), 获得一个与Socket有关的输入流对象,最后关闭IO流和socket
注意:
- 服务器的ServeSocket对象有什么用? 可以解决多并发的问题,它可以创建多个服务端socket端口来连接多个客户端socket端口,当客户端连接成功,就会通过accept()方法返回一个socket端口,注意最后也需要关闭
- 第二个socket端口有什么用?是真正用来通讯(读写数据)的端口,通过调用方法获得IO流对象,从而调用读写方法实现通讯
- 什么时候设置结束标志?输出流输出完后,要设置结束标志socket.shutdownOutput(),如果不设置,读取数据的端口不知道数据什么时候写完,就会出现卡顿;注意结束标志是端口调用的,不是输出流对象
TCP字节流案例如下:
import java.net.ServerSocket;
import java.net.Socket;//需要导入一个包
public class SocketTPC01Server {
public static void main(String[] args)throws IOException {
//思路;
//1.创建SocketSocket对象,传入端口
ServerSocket serverSocket = new ServerSocket(9999);
//这个ServerSocket是用来解决多并发的问题,它可以创建多个服务端socket端口来连接多个客户端socket
System.out.println("Server started");
//2.等待客户端连接,如果未连接,程序阻塞;
//如果连接了,返回一个Socket对象,程序继续(怎么返回一个Socket?用服务端的端口来调用,定义一个socket来接收)
Socket socket=serverSocket.accept();
System.out.println("Client connected");
//3.获得一个IO流对象
InputStream inputStream = socket.getInputStream();
//4.通过输入流,读取客户端写到数据通道的数据,并显示
byte[] buffer = new byte[1024];
int readLen = 0;
while ((readLen = inputStream.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, readLen));
}
//5.关闭输入流和Socket
serverSocket.close();//不要忘记这个也要关闭
socket.close();
inputStream.close();
}
}
package Socket;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;//注意先导入包
public class SocketTPC01Client {
public static void main(String[] args) throws IOException {
//思路:
//1.创建一个Socket对象,传入IP地址和需要连接的端口
Socket socket = new Socket(InetAddress.getLocalHost(),9999);
System.out.println("client"+socket.getClass());
//2.连接后生成Socket,通过Socket.getInputStream(),
// 获得一个与Socket有关的输入流对象
OutputStream is = socket.getOutputStream();
//3.通过输出流获取数据
is.write("hello,server".getBytes());
//4.关闭Socket和输出流
is.close();
socket.close();
}
}
TCP字符流案例如下:
//韩顺平670集(TPC字符流编程)
//演示服务端9999连接客服端,读取数据
package Socket;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketTPC03Server {
public static void main(String[] args)throws IOException {
//思路;
//1.创建Socket对象,传入端口(怎么创建Socket对象?)
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("Server started");
//2.等待客户端连接,如果未连接,程序阻塞;
//如果连接了,返回一个Socket对象,程序继续(怎么返回一个Socket?用服务端的端口来调用,定义一个socket来接收)
Socket socket=serverSocket.accept();
System.out.println("Client connected");
//3.获得一个IO流对象
InputStream inputStream = socket.getInputStream();
//4.通过字符输入流,读取客户端写到数据通道的数据,并显示
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s= bufferedReader.readLine();
System.out.println(s);
//5.获取Socket相关联的输出流
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));//通过转换流将字节流转换成字符流
bufferedWriter.write(s);
bufferedWriter.newLine();//相当于结束标记,但对方必须用readLine()来读!!!
bufferedWriter.flush(); //写完要手动刷新一下,否则数据不会写入数据通道
//设置结束标记
socket.shutdownOutput();
//6.关闭输入流和Socket
serverSocket.close();
socket.close();
bufferedWriter.close(); //用外层流来关闭
bufferedReader.close();
System.out.println("服务端退出");
}
}
package Socket;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
public class SocketTPC03Client {
public static void main(String[] args) throws IOException {
//思路:
//1.创建一个Socket对象,传入IP地址和需要连接的端口
Socket socket = new Socket(InetAddress.getLocalHost(),9999);
System.out.println("client"+socket.getClass());
//2.连接后生成Socket,通过Socket.getInputStream(),
// 获得一个与Socket有关的输出流对象
OutputStream is = socket.getOutputStream();
//3.通过输出流获取数据
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(is));
bufferedWriter.write("Hello server 字符流");
bufferedWriter.newLine();//
bufferedWriter.flush();//千万不要忘了,输出流要刷新
//设置结束标记(结束标记写在哪?输出流的后面)
socket.shutdownOutput();
//4.获得一个与Socket有关的输入流对象
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String s=bufferedReader.readLine();
System.out.println(s);
//5.关闭Socket和输出流
bufferedWriter.close();
socket.close();
bufferedReader.close();
System.out.println("客户端退出");
}
}
网络上传图片文件案例分析
代码思路:首先客户端,通过socket获得一个输入流对象,将磁盘上的图片读取到程序中,再将图片转换成字节数组,通过socket获得一个输出流对象,将字节数组写入数据通道;服务端,过socket获得一个输入流对象,将字节数组读取到程序中,然后写入文件中,最后再过socket获得一个输出流对象,返回消息收到图片
学习一定要趁热打铁,及时复习、刷题和巩固,不然基础会打不牢
第二种:UDP编程
1.说明:UDP编程没有说明客户端和服务端,只有数据的接收端和发送端,那UDP是怎么进行数据的接收和发送的?是通过DategramSocket对象的发送和接收方法,发送端将数据封装到DategramSocket对象中(或者叫装包),接收端接收到DategramSocket对象,就对其拆包,取出数据(接收和发送的都是DategramPacket对象),注意DategramSocket对象可以指定哪个端口接收数据;
DategramSocket和DategramPacket是什么?DategramSocket就是UDP编程的端口(发送端和接收端),DategramPacket是数据包,是用来封装数据的
2.通讯创建流程
3.案例分析
简单总结:接收端要接收数据,就先创建(定义)一个数据包packet来接收数据(数据包),然后拆包就可以显示数据了;而发送端要发送数据,也要先创建一个数据包packet,将要发送的数据放到到数据包里,然后发送即可
package UDP;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
//韩顺平677集(演示UDP通讯)
public class UDPReceiver {
public static void main(String[] args) throws Exception {
//1.创建DatagramSocket对象,准备在9999等待接收数据,9999是自己的端口
DatagramSocket socket = new DatagramSocket(9999);
//怎么接收数据?先创建一个数据包来储存数据
//2.创建一个DatagramPacket对象数据包(本质是一个字节数组),将数组传给对象,用来储存数据
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
//3调用方法接收数据
System.out.println("接收端A,等待接收");
socket.receive(packet);//将接收到的数据放进数据包
//4.拆包,调用packet方法获得接收到的数据字节大小和数据,创建一个字符串对象传进去
int length = packet.getLength();
byte[] data = packet.getData();
String s = new String(data, 0, length);
System.out.println(s);
//5.接收端退出
System.out.println("接收端A关闭");
socket.close();
}
}
ckage UDP;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
//韩顺平677集(演示UDP通讯)
public class UDPSender {
public static void main(String[] args) throws Exception {
//1.创建一个DatagramSocket对象,在9998端口等待接收数据
//为什么不是在9999端口接收?接收端和发送端不能是同一个端口
DatagramSocket socket = new DatagramSocket(9998);
//2.装包,将要发送的数据封装到数据包里
//怎么写我们要发送的数据?将我们要发送的数据先转换成字节数组(调用getByte方法),再将数据、数据字节长度、主机地址、要发送的端口传进数据包对象里
byte[] data = "你好,小医仙".getBytes();
DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName("127.0.0.1"), 9999);
//3.发送数据
System.out.println("发送端B,等待发送");
//将我们要发送的数据封装到packet里,然后将packet数据包发送出去
socket.send(packet);
//4.发送端退出
System.out.println("发送端B关闭");
socket.close();
}
}
4.TCP和UDP的区别
UDP是通过数据包的装包和拆包进行通讯,而TCP是通过IO流,创建数据通道进行通讯
(4).何时用?
四、相关知识点
1.netstat指令
netstat -an :指令是用来查看主机网络情况的,端口连接情况和网络连接情况
netstat -an |more :分页显示
在win+r 命令窗口中打开;
说明:
- listering 表达有某个端口在监听
- 如果有客户端连接到主机,就会显示一个外部地址
- ctrl+c 退出程序
2.当客户端连接服务端时,实际上也是通过一个端口与服务端进行连接的,但是这个端口是TCP/ip随机分配的,不是确定的(这就是为什么学高并发时,端口是有限的,端口会出现冲突)