教程
狂神说java官网
B站视频链接
要素
- 两个主要的问题:如何准确定位到网络上的一台或多台主机;找到主机之后如何通信。
- 网络编程中的要素:IP和端口号;网络通信协议。
- 万物皆对象。
IP
- IP地址:InterAddress,唯一定位一台网络上的计算机。
- 127.0.0.1:本机localhost。
- ip地址分类:
- ipv4 / ipv6
- 公网(互联网)-私网(局域网)
- 域名:记忆IP问题
public class TestIP { public static void main(String[] args) { try { InetAddress inetAddress1 = InetAddress.getLocalHost(); System.out.println(inetAddress1); InetAddress inetAddress2 = InetAddress.getByName("www.baidu.com"); System.out.println(inetAddress2); System.out.println(inetAddress2.getCanonicalHostName()); System.out.println(inetAddress2.getHostAddress()); System.out.println(inetAddress2.getHostName()); } catch (UnknownHostException e) { e.printStackTrace(); } } }
|
端口
不同的端口有不同的端口号,用来区分软件。
0-65535被规定。单个协议下,端口号不能冲突。
端口分类:
- 公用端口 0-1023
- HTTP: 80
- HTTPS: 443
- FTP: 21
- Telent: 23
- 程序注册端口 1024-49151,分配用户或者程序
- Tomcat: 8080
- MySQL: 3306
- Oracle: 1521
- 动态、私有 49152-65535
netstat -ano netstat -ano|findstr "10000" tasklist|findstr "10000"
|
public class TestSocket { public static void main(String[] args) { InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 8080); InetSocketAddress socketAddress2 = new InetSocketAddress("localhost", 8080); System.out.println(socketAddress); System.out.println(socketAddress2);
System.out.println(socketAddress.getAddress()); System.out.println(socketAddress.getHostName()); System.out.println(socketAddress.getPort()); } }
|
通信协议
网络通信协议:速率、传输码率、代码结构、传输控制……
TCP用户传输协议 |
UDP用户数据报协议 |
连接,稳定 |
不连接,不稳定 |
客户端、服务端 |
没有明确的界限 |
三次握手,四次挥手 |
不管是否准备好,都可以发 |
传输完成,释放连接,效率低 |
DDOS攻击、饱和攻击 |
TCP实现聊天
public class TCPServerDemo1 { public static void main(String[] args) { try (ServerSocket serverSocket = new ServerSocket(9999); Socket socket = serverSocket.accept(); InputStream is = socket.getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream() ) { byte[] buffer = new byte[1024]; int len; while ((len = is.read(buffer)) != -1) { baos.write(buffer, 0, len); } System.out.println(baos); } catch (IOException e) { e.printStackTrace(); } } }
|
public class TCPClientDemo1 { public static void main(String[] args) { Socket socket = null; OutputStream os = null; try { InetAddress serverIP = InetAddress.getByName("127.0.0.1"); socket = new Socket(serverIP, 9999); os = socket.getOutputStream(); os.write("nb".getBytes()); } catch (IOException e) { e.printStackTrace(); } finally { if (os != null) { try { os.close(); } catch (IOException e) { e.printStackTrace(); } } if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
|
客户端使用的是比较冗长的写法,将各种资源的close()
方法写在finally
块中,同时加入各自的catch
块。服务端使用的是try-with-resources语句,更简洁。
如果需要服务端不断监听并收取消息,需使用循环语句改写代码。
Java——IO流超详细总结
TCP实现文件上传
public class TCPServerDemo2 { public static void main(String[] args) { try (ServerSocket serverSocket = new ServerSocket(9000); Socket socket = serverSocket.accept(); InputStream is = socket.getInputStream(); OutputStream os = socket.getOutputStream(); FileOutputStream fos = new FileOutputStream("receive.jpg")) { byte[] buffer = new byte[1024]; int len; while ((len = is.read(buffer)) != -1) { fos.write(buffer, 0, len); } os.write("Received".getBytes()); } catch (IOException e) { e.printStackTrace(); } } }
|
public class TCPClientDemo2 { public static void main(String[] args) { try (Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9000); InputStream is = socket.getInputStream(); OutputStream os = socket.getOutputStream(); FileInputStream fis = new FileInputStream("hitpt.jpg"); ByteArrayOutputStream baos = new ByteArrayOutputStream()) { byte[] buffer = new byte[1024]; int len; while ((len = fis.read(buffer)) != -1) { os.write(buffer, 0, len); } socket.shutdownOutput(); System.out.println("Sent"); while ((len = is.read(buffer)) != -1) { baos.write(buffer, 0, len); } System.out.println("Server: " + baos); } catch (IOException e) { e.printStackTrace(); } } }
|
UDP
连续发送消息
public class UDPSenderDemo { public static void main(String[] args) { try (DatagramSocket socket = new DatagramSocket(8888); BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) { while (true) { String dataString = reader.readLine(); byte[] data = dataString.getBytes(); DatagramPacket packet = new DatagramPacket(data, 0, data.length, new InetSocketAddress("localhost", 6666)); socket.send(packet); if (dataString.equals("bye")) { break; } } } catch (IOException e) { e.printStackTrace(); } } }
|
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket;
public class UDPReceiverDemo { public static void main(String[] args) { try (DatagramSocket socket = new DatagramSocket(6666)) { while (true) { byte[] container = new byte[1024]; DatagramPacket packet = new DatagramPacket(container, 0, container.length); socket.receive(packet); String data = new String(packet.getData(), 0, packet.getLength()); System.out.println(packet.getSocketAddress() + " --> " + data); if (data.equals("bye")) { break; } } } catch (IOException e) { e.printStackTrace(); } } }
|
两端平等,无C/S概念。
聊天工具实现
基于上例,再利用多线程来实现。
public class TalkSend implements Runnable { DatagramSocket socket = null; BufferedReader reader = null;
private final String toIP; private final int toPort;
public TalkSend(String toIP, int fromPort, int toPort) { this.toIP = toIP; this.toPort = toPort; try { this.socket = new DatagramSocket(fromPort); this.reader = new BufferedReader(new InputStreamReader(System.in)); } catch (SocketException e) { e.printStackTrace(); } }
@Override public void run() { while (true) { try { String dataString = this.reader.readLine(); byte[] data = dataString.getBytes(); DatagramPacket packet = new DatagramPacket(data, 0, data.length, new InetSocketAddress(this.toIP, this.toPort)); socket.send(packet); if (dataString.equals("bye")) { break; } } catch (IOException e) { e.printStackTrace(); } } try { reader.close(); } catch (IOException e) { e.printStackTrace(); } socket.close(); } }
|
public class TalkReceive implements Runnable { DatagramSocket socket = null;
public TalkReceive(int port) { try { this.socket = new DatagramSocket(port); } catch (SocketException e) { e.printStackTrace(); } }
@Override public void run() { while (true) { byte[] container = new byte[1024]; DatagramPacket packet = new DatagramPacket(container, 0, container.length); try { this.socket.receive(packet); String data = new String(packet.getData(), 0, packet.getLength()); System.out.println(packet.getSocketAddress() + " --> " + data); if (data.equals("bye")) { break; } } catch (IOException e) { e.printStackTrace(); } } socket.close(); } }
|
假设,学生和老师要聊天。
public class TalkStudent { public static void main(String[] args) { new Thread(new TalkSend("localhost", 6666, 8888)).start(); new Thread(new TalkReceive(7777)).start(); } }
|
public class TalkTeacher { public static void main(String[] args) { new Thread(new TalkSend("localhost", 5555, 7777)).start(); new Thread(new TalkReceive(8888)).start(); } }
|
注意端口间的对应关系即可。
URL
Uniform Resource Locator,统一资源定位器,定位资源的,定位互联网上的某一个资源。
协议://ip地址:端口:/项目名/资源
public class TestURLDemo1 { public static void main(String[] args) { try { URL url = new URL("http://localhost:8080/helloworld/index.jsp?key=123"); System.out.println(url.getProtocol()); System.out.println(url.getHost()); System.out.println(url.getPort()); System.out.println(url.getPath()); System.out.println(url.getFile()); System.out.println(url.getQuery()); } catch (MalformedURLException e) { e.printStackTrace(); } } }
|
public class TestURLDemo2 { public static void main(String[] args) { try { URL url = new URL("https://img.lfalive.top/PT/hitpt.JPG"); HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); InputStream inputStream = urlConnection.getInputStream(); FileOutputStream fos = new FileOutputStream("download.jpg"); byte[] buffer = new byte[1024]; int len; while ((len = inputStream.read(buffer)) != -1) { fos.write(buffer,0, len); } fos.close(); inputStream.close(); urlConnection.disconnect(); } catch (IOException e) { e.printStackTrace(); } } }
|