网络编程
网络概念
两台设备通过网络进行数据传输
网络通信:将数据通过网络从一台设备传输到另一台设备
java.net包下面提供了一系列接口和类供程序员使用
ip地址:用于唯一标识网络中每台设备
ip查看:ipconfig
ip地址形式:点分十进制xxx.xx.xxx.xx
每一个十进制的范围是0-255
ip地址由网络地址和主机地址组成
域名,为了方便记忆,将ip地址映射为域名
端口号,用于表示计算机上某个特定的网络程序,以整数形式表示,范围0-65535
0-1024已经被系统占用,ssh21 ftp21,smtp25 http80
常见网络程序端口号:
tomcat 8080
mysql 3306
TCP:
- 使用TCP协议前,需先建立TCP连接,形成传输数据通道
- 传输前采用三次握手方式建立,是可靠的
- TCP进行通信的两个进程是:客户端、服务端
- 在连接中可进行大数据量的传输
- 传输完毕,需要释放已经建立的连接,效率低
UDP:
- 将数据,源,目的封装成数据包,不需要建立连接
- 每个数据报的大小限制在64kb以内,不适合传输大量数据
- 不可靠的连接
- 发送数据结束以后,无需释放连接资源,所以速度比较快
InetAddress
//获取本机的InetAddress对象
InetAddress host = InetAddress.getLocalHost();
System.out.println(host);
//通过计算机名获取InetAddress对象
InetAddress host1 = InetAddress.getByName("LAPTOP-PAOUUF6C");
System.out.println(host1);
//通过域名获取InetAddress对象
InetAddress host2 = InetAddress.getByName("www.baidu.com");
System.out.println(host2);
//通过InetAddress获取主机名和主机地址
String address =host2.getHostAddress();
String name = host2.getHostName();
System.out.println(address + " - " + name);
Socket
套接字开发网络应用程序被广泛采用,以至于成为事实上的标准,通信的两端都要有Socket,是两台机器间通信的端点,网络通信其实就是Socket通信。Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO进行传输,一般主动发起通信的应用程序是客户端,等待通信连接的是服务端。Socket编程分为TCP编程和UDP编程。
//建立TCP连接,客户端向服务端发送一个数据,服务端显示
//服务器代码
//Socket中TCP编程Service端
//在服务端开启一个9999端口的服务
ServerSocket serverSocket = new ServerSocket(9999);
//监听,等待来自客户端的Socket连接,没有客户端没有连接,程序将一直阻塞在这里
System.out.println("服务端9999端口已经开启,等待连接");
Socket socket = serverSocket.accept();
System.out.println("服务器 Socket: " + socket.getClass());
//接受客户端数据并输出
InputStream inputStream = socket.getInputStream();
byte[] buff = new byte[1024];
int readLength = 0;
while((readLength = inputStream.read(buff)) != -1){
System.out.println(new String(buff,0,readLength));
}
//关闭资源
inputStream.close();
socket.close();
serverSocket.close();
//客户端代码
//Socket中TCP编程 Client端
//开启一个Socket连接,向服务端的9999发起一个Socket连接
Socket socket = new Socket(InetAddress.getLocalHost(),9999);
System.out.println("客户端 socket:" + socket.getClass());
//向服务端发送数据
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello server".getBytes());
System.out.println("客户端数据发送完成,关闭连接");
//关闭连接和IO资源
outputStream.close();
socket.close();
通过TCP编程客户端向服务端发送一条数据,服务端响应一条数据
//服务端
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端开启9999端口,等待客户端连接");
Socket socket = serverSocket.accept();
//等到客户端连接之后,显示客户端发送数据
InputStream inputStream = socket.getInputStream();
byte[] buff = new byte[1024];
int length = 0;
while((length = inputStream.read(buff)) != -1){
System.out.println(new String(buff,0,length));
}
//服务端响应一个数据
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello client".getBytes());
socket.shutdownOutput();//向客户端发送一个结束发送的标记
//关闭资源
outputStream.close();
inputStream.close();
socket.close();
serverSocket.close();
//客户端
//向服务端建立连接
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
//向服务端发送数据
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello server".getBytes());
socket.shutdownOutput();//发送一个服务端结束发送数据的标记
//等待服务端响应
byte[] buff = new byte[1024];
int length = 0;
InputStream inputStream = socket.getInputStream();
while((length = inputStream.read(buff)) != -1){
System.out.println(new String(buff,0,length));
}
System.out.println("客户端退出");
//关闭资源
inputStream.close();
outputStream.close();
socket.close();
使用字符流来实现客户端和服务端通信,我们就需要使用转换流,把对应的字节流转换成字符流,我们使用字符流的时候,可以使用newLine()作为结束发送的标记,使用字符流输出的时候一定要使用flush刷新,不然数据不会输出。
//服务端
//服务端开启一个9999端口
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端已开启,服务端正在监听9999端口");
//监听端口
Socket socket = serverSocket.accept();
//输出客户端数据
InputStream inputStream = socket.getInputStream();
//使用字符流
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String str = reader.readLine();
System.out.println(str);
//服务端响应客户端数据
OutputStream outputStream = socket.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
writer.write("hello client 字符流");
writer.newLine();//设置输出结束标识
writer.flush();//刷新缓冲区,输出数据
System.out.println("服务端退出");
//关闭IO资源
writer.close();
reader.close();
socket.close();
serverSocket.close();
//客户端
//开启一个到服务端连接
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
System.out.println("客户端连接建立");
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);
System.out.println("客户端退出");
reader.close();
writer.close();
socket.close();
文件上传
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端正在监听9999端口");
Socket socket = serverSocket.accept();
//获取客户端数据
InputStream inputStream = socket.getInputStream();
String descPath = "d:\\1.jpg";
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(descPath));
byte[] buff = new byte[1024];
int length = 0;
while((length = inputStream.read(buff)) != -1){
bos.write(buff,0,length);//将文件存入到服务器
}
System.out.println("接受文件完成");
//向服务器端发送接受图片完成
OutputStream outputStream = socket.getOutputStream();
outputStream.write("接受图片完成".getBytes());
socket.shutdownOutput();//发送结束标记
//关闭资源
System.out.println("服务器退出");
outputStream.close();
bos.close();
inputStream.close();
socket.close();
serverSocket.close();
//客户端
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
//使用字节流向服务器发送一张图片
//从本地读取图片文件
String picPath = "e:\\1.jpg";
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(picPath));
OutputStream outputStream = socket.getOutputStream();
//一次性获得要输出的字节数组
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int length = 0;
while((length = bis.read(buff)) != -1){
bos.write(buff,0,length);
}
//得到要传输的总数据
byte[] data = bos.toByteArray();
//一次性向服务器传输
outputStream.write(data,0,data.length);
socket.shutdownOutput();//发送一个传输结束标记
System.out.println("客户端发送图片完成");
//等待服务器端响应
InputStream inputStream = socket.getInputStream();
while((length = inputStream.read(buff)) != -1){
System.out.println(new String(buff,0,length));
}
//关闭资源
inputStream.close();
outputStream.close();
bos.close();
bis.close();
socket.close();
在UDP编程中没有明确的客户端和服务端,变成了数据接收端和发送端,接受数据和发送数据是通过DatagramSocket对象完成,将数据封装到DatagramPacket对象/装包,当接受到DataPacket对象需要进行拆包,取出数据,DatagramSocket可以指定在哪个端口接受数据。
//接收端
//接收端打开一个UDP端口9999
DatagramSocket socket = new DatagramSocket(9999);
byte[] data = new byte[1024];
//封装DatagramPacket准备接受数据
DatagramPacket packet = new DatagramPacket(data,data.length);
System.out.println("接受端9999监听");
socket.receive(packet);//接受发送端数据,程序会一直阻塞在这里等待发送端发送数据,当接收到数据就继续执行
//打印发送端数据
data = packet.getData();
int length = packet.getLength();
System.out.println(new String(data,0,length));
//接收端回复数据
data = "ok,明天见".getBytes();
packet = new DatagramPacket(data,data.length, InetAddress.getByName("100.64.222.199"),9998);
socket.send(packet);
System.out.println("接收端退出");
socket.close();//关闭资源
//发送端
//发送端打开一个UTP9998端口
DatagramSocket socket = new DatagramSocket(9998);
byte[] data = "hello,明天去从火锅".getBytes();
DatagramPacket packet = new DatagramPacket(data,data.length,InetAddress.getByName("100.64.222.199"),9999);
//发送端发送数据
socket.send(packet);
//发送端准备接受数据
socket.receive(packet);
data = packet.getData();
int length = packet.getLength();
System.out.println(new String(data,0,length));
System.out.println("发送端退出");
//关闭资源
socket.close();