Java网络编程小结
关于网络编程
网络分层模型
在计算机网络中出于设计方便(分层可以降低网络问题的整体复杂度,分模块的思想本是就是一种设计思想)、功能独立(每一层有自己的独立分工,各不干扰)、易于维护(由于上层网络都是以下层网络提供的接口为基础实现自己的功能业务,只要下层接口及提供的服务不变,上层网络仅仅需要关注自己所在层)等等目的,现在的网络普遍采用分层次的网络模型,其中就有经典的OSI七层模型和简化的五层模型,简化的五层模型比较实用。
- 应用层的我们每天都在接触,日常的开发都是在应用层,更底层的东西就不是我们考虑的了
- 我们这次重点关注运输层的TCP与UDP
- TCP与UDP各有特点,如TCP是有连接的,提供流量控制、拥塞控制、可靠数据传输等等机制,但是不存在完美的食物,在提供了这么多服务的同时TCP也需要消耗更多的资源和占用更多的时间开销;相比较UDP只是提供了最基本的运输层服务如数据传输、差错检测,这也意味着UDP传输不会对传输速率进行限制以防丢包
- TCP与UDP又有自己的应用环境,例如邮件、网页等等都是使用TCP协议,毕竟这类应用需要严格的正确报文,需要TCP提供的可靠数据传输服务,而如视频通话类似的应用出于对高传输速率的要求和对数据丢包的一定可容忍度,反而可能会考虑UDP协议
主要使用知识
InetAddress
InetAddress类没有构造方法,所以不能直接new出一个对象,但是可以使用InetAddress类的静态方法获得该类的实例对象。
import java.net.InetAddress;
import java.net.UnknownHostException;
public class TestInetAddress {
public static void main(String[] args) throws UnknownHostException {
InetAddress inetAddress1 = InetAddress.getByName("localhost");
//通过getByName()方法获得本机的InetAddrss对象
InetAddress inetAddress2 = InetAddress.getLocalHost();
//使用getLocalHost()方法直接获得本机的InetAddrss对象
InetAddress inetAddress3 = InetAddress.getByName("www.baidu.com");
//getByName()方法参数也可以传入一个域名字符串
System.out.println(inetAddress1);
System.out.println(inetAddress2);
System.out.println(inetAddress3);
System.out.println(inetAddress3.getAddress());
System.out.println(inetAddress3.getHostAddress());
System.out.println(inetAddress3.getCanonicalHostName());
System.out.println(inetAddress2.getHostName());
}
}
localhost/127.0.0.1
DESKTOP-IJLP772/169.254.103.159
www.baidu.com/14.215.177.39
[B@74a14482
14.215.177.39
14.215.177.39
www.baidu.com
SocketAddress
套接字Socket相当于IP地址与端口号的组合,SocketAddress是一个抽象类,需要由子类完成具体的功能实现。
InetSocketAddress类是SocketAddress类的直接子类,实现了IP套接字(socket)地址的封装。
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
public class TestInetSocketAddress {
public static void main(String[] args) throws UnknownHostException {
InetSocketAddress socketAddress = new InetSocketAddress("localhost", 8080);
System.out.println(socketAddress);//socket对象,有主机名、IP、端口号信息
System.out.println(socketAddress.getAddress());//主机名、IP地址信息
System.out.println(socketAddress.getHostName());//主机名
System.out.println(socketAddress.getPort());//端口号信息
}
}
localhost/127.0.0.1:8080
localhost/127.0.0.1
localhost
8080
URL
统一资源定位器,由4部分组成:协议、主机、端口、路径
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class TestURL {
public static void main(String[] args) throws Exception {
URL url = new URL("http://localhost:8080/hello/index.txt?username=kk&password=123456");
System.out.println(url.getPort());
//获得端口号
System.out.println(url.getFile());
//获得文件路径,包含附加参数信息
System.out.println(url.getHost());
//获得主机名
System.out.println(url.getPath());
//获得文件路径
System.out.println(url.getProtocol());
//获得使用的协议
System.out.println(url.getQuery());
//获得附加参数信息
url = new URL("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimage.zzd.sm.cn%2F16702215880693533448.jpg%3Fid%3D0&refer=http%3A%2F%2Fimage.zzd.sm.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1628674831&t=42ff5a6450aedc85f0ae407e6d77b165");
//url现在指向一个图片文件
HttpURLConnection httpURLConnection= (HttpURLConnection) url.openConnection();
//建立Http连接
InputStream inputStream = httpURLConnection.getInputStream();
//获得文件输入流
FileOutputStream fileOutputStream = new FileOutputStream(new File("url.jpg"));
//获得文件输出流
byte[] buffer = new byte[1024];
//设置输入输出流之间的中间缓冲区
int len;
while ((len=inputStream.read(buffer))!=-1){
fileOutputStream.write(buffer,0,len);
}
//遍历输入流把图片文件信息写入字节数组中,同时把字节数组中的信息写入文件输出流中
fileOutputStream.close();
inputStream.close();
httpURLConnection.disconnect();
//关闭各种流资源,避免浪费
}
}
8080
/hello/index.txt?username=kk&password=123456
localhost
/hello/index.txt
http
username=kk&password=123456
TCP网络编程
单方向接受client—>server
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class TcpClientDemo01 {
public static void main(String[] args) {
InetAddress inetAddress = null;
Socket socket = null;
OutputStream outputStream =null;
try {
//首先知道服务器的地址和端口号
inetAddress = InetAddress.getByName("127.0.0.1");
int port = 8055;
//连接服务器
socket = new Socket(inetAddress, port);
//发送消息
outputStream = socket.getOutputStream();
outputStream.write("你好,我是客户端Java".getBytes());
} catch (Exception e) {
e.printStackTrace();
}finally {
if (outputStream!=null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServerDemo01 {
public static void main(String[] args) {
ByteArrayOutputStream byteArrayOutputStream = null;
InputStream inputStream = null;
Socket socket = null;
try {
//首先有一个地址
ServerSocket serverSocket = new ServerSocket(8055);
//等待客户端连接
while (true){
socket = serverSocket.accept();
inputStream = socket.getInputStream();
//接受消息
int len;
byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
while ((len=inputStream.read(buffer))!=-1){
byteArrayOutputStream.write(buffer,0,len-1);
}
System.out.println(byteArrayOutputStream.toString());
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if (byteArrayOutputStream!=null){
try {
byteArrayOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStream!=null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
双向单次回答 client<----->server
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class TcpClientDemo2 {
public static void main(String[] args) throws Exception {
//创建连接套接字
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9000);
//创建一个输出流
OutputStream os = socket.getOutputStream();
//获取文件输入流
FileInputStream fileInputStream = new FileInputStream(new File("1.jpg"));
//文件上传
int len;
byte [] buffer = new byte[1024];
while ((len=fileInputStream.read(buffer))!=-1){
os.write(buffer,0,len);
}
//通知服务器上传完毕
socket.shutdownOutput();
//等待服务器接受成功的响应
InputStream inputStream = socket.getInputStream();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer2 = new byte[1024];
int len2;
while ((len2=inputStream.read(buffer2))!=-1){
byteArrayOutputStream.write(buffer2,0,len2);
}
System.out.println(byteArrayOutputStream.toString());
//关闭资源
byteArrayOutputStream.close();
inputStream.close();
fileInputStream.close();
os.close();
socket.close();
}
}
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServerDemo2 {
public static void main(String[] args) throws Exception {
//创建一个地址,端口号
ServerSocket serverSocket = new ServerSocket(9000);
//等待客户端连接
Socket socket = serverSocket.accept();
//获取输入流
InputStream inputStream = socket.getInputStream();
//获取文件输出流
FileOutputStream fileOutputStream = new FileOutputStream(new File("1x.jpg"));
//写入文件
int len;
byte[] buffer = new byte[1024];
while ((len=inputStream.read(buffer))!=-1){
fileOutputStream.write(buffer,0,len);
}
//通知客户端接受完成
OutputStream outputStream = socket.getOutputStream();
outputStream.write("服务器接受完毕".getBytes());
//关闭资源
outputStream.close();
fileOutputStream.close();
inputStream.close();
socket.close();
serverSocket.close();
}
}
UDP网络编程
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
//无连接
public class UdpClientDemo1 {
public static void main(String[] args) throws Exception {
//建立一个Socket
DatagramSocket socket = new DatagramSocket(9000);
//建立一个packet
String msg = "你好啊,服务器!!!";
DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, InetAddress.getByName("127.0.0.1"), 9090);
//发送包
socket.send(packet);
//释放资源
socket.close();
}
}
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UdpServerDemo1 {
public static void main(String[] args) throws Exception {
//建立一个Socket
DatagramSocket socket = new DatagramSocket(9090);
//建立一个packet
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
//接受包
socket.receive(packet);
System.out.println(new String(packet.getData(),0, packet.getLength()));
System.out.println(new String(buffer,0, packet.getLength()));
System.out.println(packet.getAddress().getHostAddress());
System.out.println(packet.getPort());
//释放资源
socket.close();
}
}
你好啊,服务器!!!
你好啊,服务器!!!
127.0.0.1
9000
聊天功能控制台实现
不使用多线程的方法
package edu.net;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.*;
public class UdpSenderDemo1 {
public static void main(String[] args) throws Exception {
//创建socket,需要自己端口号
DatagramSocket socket = new DatagramSocket(9999);
//模拟输入
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true){
String msg = reader.readLine();
byte[] data = msg.getBytes();
byte[] buffer = new byte[1024];//供接受包使用
DatagramPacket packet = new DatagramPacket(data, 0, data.length, new InetSocketAddress("127.0.0.1", 6666));
socket.send(packet);
if (msg.equals("bye")){
break;
}
//发送完毕等待对方信息带来
DatagramPacket packet1 = new DatagramPacket(buffer, 0, buffer.length);
socket.receive(packet1);//阻塞式接受,会等待
System.out.println("对方:"+new String(packet1.getData(),0,packet1.getLength()));
}
reader.close();
socket.close();
}
}
package edu.net;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
public class UdpReceiverDemo1 {
public static void main(String[] args) throws Exception {
//创建socket,需要自己端口号
DatagramSocket socket = new DatagramSocket(6666);
//模拟输入
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
byte[] buffer = new byte[1024];//供接受包使用
String data;
while (true){
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
socket.receive(packet);//阻塞式接受,会等待
data = new String(packet.getData(),0, packet.getLength());
System.out.println("对方:"+data);
if (data.equals("bye")){
break;
}
//接受成功显示信息后开始回复对方
data = reader.readLine();
DatagramPacket packet1 = new DatagramPacket(data.getBytes(), 0, data.getBytes().length, new InetSocketAddress("127.0.0.1", 9999));
socket.send(packet1);
}
reader.close();
socket.close();
}
}
使用多线程的方法
package edu.net;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
public class UdpSenderDemo2 implements Runnable{
private DatagramSocket socket;
private BufferedReader reader;
private int fromPort;
private String toIP;
private int toPort;
public UdpSenderDemo2(int fromPort, String toIP, int toPort) {
this.fromPort = fromPort;
this.toIP = toIP;
this.toPort = toPort;
try {
socket = new DatagramSocket(fromPort);
} catch (SocketException e) {
e.printStackTrace();
}
reader = new BufferedReader(new InputStreamReader(System.in));
}
@Override
public void run() {
while (true){
try {
String msg = reader.readLine();
byte[] data = msg.getBytes();
DatagramPacket packet = new DatagramPacket(data, 0, data.length, new InetSocketAddress(this.toIP, this.toPort));
socket.send(packet);
if (msg.equals("bye")){
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
socket.close();
}
}
package edu.net;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UdpReceiverDemo2 implements Runnable{
private DatagramSocket socket;
private BufferedReader reader;
private int fromPort;
byte[] buffer;
public UdpReceiverDemo2(int fromPort) {
this.fromPort = fromPort;
this.buffer = new byte[1024];
try {
socket = new DatagramSocket(fromPort);
} catch (SocketException e) {
e.printStackTrace();
}
reader = new BufferedReader(new InputStreamReader(System.in));
}
@Override
public void run() {
String data;
while (true){
try {
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
socket.receive(packet);
data = new String(packet.getData(),0, packet.getLength());
System.out.println("对方:"+data);
if (data.equals("bye")){
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
socket.close();
}
}
public class Student {
public static void main(String[] args) {
UdpSenderDemo2 udpSenderDemo2 = new UdpSenderDemo2(6666, "127.0.0.1", 9999);
UdpReceiverDemo2 udpReceiverDemo2 = new UdpReceiverDemo2(7777);
new Thread(udpSenderDemo2).start();
new Thread(udpReceiverDemo2).start();
//这种代码需要双方都说bye才能结束进程,仅仅一方bye,只有该方send线程和对方receive线程关闭,需要对方也说bye才能关闭4个线程
}
}
public class Teacher {
public static void main(String[] args) {
UdpSenderDemo2 udpSenderDemo2 = new UdpSenderDemo2(8888, "127.0.0.1", 7777);
UdpReceiverDemo2 udpReceiverDemo2 = new UdpReceiverDemo2(9999);
new Thread(udpSenderDemo2).start();
new Thread(udpReceiverDemo2).start();
//这种代码需要双方都说bye才能结束进程,仅仅一方bye,只有该方send线程和对方receive线程关闭,需要对方也说bye才能关闭4个线程
}
}
|