1 概述
- 参考链接 【狂神说Java】网络编程实战讲解
-
java网络编程主要针对传输层的 TCP/UDP 编程
-
网络编程中主要的两个问题
- 如何准确的定位到网络上的一台或者多台主机
// 补充:用 ping命令 // 如 ping www.baidu.com,返回如下内容 正在 Ping www.a.shifen.com [180.101.49.12] 具有 32 字节的数据: // IP 即 180.101.49.12 来自 180.101.49.12 的回复: 字节=32 时间=10ms TTL=53 来自 180.101.49.12 的回复: 字节=32 时间=7ms TTL=53 来自 180.101.49.12 的回复: 字节=32 时间=8ms TTL=53 来自 180.101.49.12 的回复: 字节=32 时间=9ms TTL=53
- 找到主机后如何进行通信
- 如何准确的定位到网络上的一台或者多台主机
-
网络编程中的要素
- IP 和 端口号
- 网络通信协议
2 代码
2.1 TCP Demo
案例1:TCP实现聊天
- 客户端
public class SocketClient { public static void main(String[] args) { Socket socket = null; OutputStream os = null; try { InetAddress ip = InetAddress.getByName("127.0.0.1"); socket = new Socket(ip, 9999); os = socket.getOutputStream(); os.write("你好,网络编程".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(); } } } } }
- 服务端
public class SocketServer { public static void main(String[] args) { ServerSocket serverSocket = null; Socket socket = null; InputStream is = null; ByteArrayOutputStream baos = null; try { // 创建服务端连接,默认ip = 127.0.0.1,端口设置为 9999 // 因此完整服务端地址为 127.0.0.1:9999 serverSocket = new java.net.ServerSocket(9999); // 表示一直监听,没 while (true) 循环接收数据一次程序就终止了 // while (true) { socket = serverSocket.accept(); is = socket.getInputStream(); // 管道流 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.toString()); // } } catch (IOException e) { e.printStackTrace(); } finally { // 释放资源(从后往前释放) if (baos != null) { try { baos.close(); } catch (IOException e) { e.printStackTrace(); } } if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } if (serverSocket != null) { try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
案例2:文件上传
-
客户端
public class SocketClient2 { public static void main(String[] args) throws IOException { Socket socket = new Socket("127.0.0.1", 9001); OutputStream os = socket.getOutputStream(); // 读取文件(即读取根路径下的 1.jpg) FileInputStream fis = new FileInputStream(new File("input.jpg")); // 写出文件 byte[] buffer = new byte[1024]; int len; while ((len = fis.read(buffer)) != -1) { os.write(buffer, 0, len); } // 通知服务器自己已经写完了 socket.shutdownOutput(); // 下面这段代码处理服务器的响应 "我接受完毕了,你可以断开了" InputStream inputStream = socket.getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer2 = new byte[1024]; int len2; while ((len2 = inputStream.read(buffer2)) != -1) { baos.write(buffer2, 0, len2); } System.out.println(baos.toString()); // 释放资源 baos.close(); inputStream.close(); fis.close(); os.close(); socket.close(); } }
-
服务端
public class SocketServer2 { // 上次用的捕获异常,这次用抛异常(但实际项目中建议使用捕获方式而不是直接抛) public static void main(String[] args) throws IOException { // 1. 创建服务 ServerSocket serverSocket = new ServerSocket(9001); // 2. 监听客户端的连接(阻塞式监听) Socket socket = serverSocket.accept(); // 3. 获取输入流 InputStream is = socket.getInputStream(); // 4. 文件输出,输出的文件名为根路径下的 receive.jpg FileOutputStream fos = new FileOutputStream(new File("output.jpg")); byte[] buffer = new byte[1024]; int len; while ((len = is.read(buffer)) != -1) { fos.write(buffer, 0, len); } // 通知客户端我已经接收完毕了 OutputStream os = socket.getOutputStream(); os.write("我接受完毕了,你可以断开了".getBytes()); // 释放资源 fos.close(); is.close(); socket.close(); serverSocket.close(); } }
2.2 UDP Demo
案例1:UDP实现发送消息
- 注:UDP发送端、接收端的地位是平等的,可以互发。不像TCP那样,客户端是 Socket 服务端是 ServerSocket ,而 UDP 发送接收端都是 DatagramSocket
-
发送端
public class UdpSend { public static void main(String[] args) throws IOException { // 1. 建立一个 socket DatagramSocket socket = new DatagramSocket(); /** * 2. 创建数据包 * * 参数说明 * public DatagramPacket(byte buf[], int offset, int length, InetAddress address, int port) * buf:he packet data. * offset:the packet data offset. * length:the packet data length. * address:the destination address. * port:the destination port number. */ String msg = "你好,UDP!"; DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, InetAddress.getByName("localhost"), 9999); // 3. 发送包 socket.send(packet); // 4. 释放资源 socket.close(); } }
-
接收端
public class UdpReceive { public static void main(String[] args) throws Exception { DatagramSocket socket = new DatagramSocket(9999); // 接收数据包 byte[] buffer = new byte[1024]; DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length); socket.receive(packet); System.out.println(packet.getAddress().getHostAddress()); System.out.println(new String(packet.getData(), 0, packet.getLength())); socket.close(); } }
案例2
- 发送端
public class UdpSendDemo { public static void main(String[] args) throws Exception { DatagramSocket socket = new DatagramSocket(8888); // 控制台读取数据 BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); while (true) { String data = reader.readLine(); DatagramPacket packet = new DatagramPacket(data.getBytes(), 0, data.getBytes().length, InetAddress.getByName("localhost"), 6666); socket.send(packet); if (data.equals("bye")) { break; } } socket.close(); } }
- 接收端
public class UdpReceiveDemo { public static void main(String[] args) throws Exception { DatagramSocket socket = new DatagramSocket(6666); while (true) { byte[] buffer = new byte[1024]; DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length); socket.receive(packet); String receiveData = new String(packet.getData(), 0, packet.getData().length); System.out.println(receiveData); if (receiveData.equals("bye")) { break; } } socket.close(); } }
案例3:多线程在线咨询
- TalkSend 线程
public class TalkSend implements Runnable { DatagramSocket socket = null; BufferedReader reader = null; private int fromPort; private String toIP; private int toPort; public TalkSend(int fromPort, String toIP, int toPort) { this.fromPort = fromPort; this.toIP = toIP; this.toPort = toPort; try { socket = new DatagramSocket(fromPort); reader = new BufferedReader(new InputStreamReader(System.in)); } catch (SocketException e) { e.printStackTrace(); } } public void run() { while (true) { try { String data = reader.readLine(); DatagramPacket packet = new DatagramPacket(data.getBytes(), 0, data.getBytes().length, InetAddress.getByName(this.toIP), this.toPort); socket.send(packet); if (data.equals("bye")) { break; } } catch (Exception e) { e.printStackTrace(); } } } }
- TalkReceive 线程
public class TalkReceive implements Runnable { DatagramSocket socket = null; private int port; private String msgFrom; public TalkReceive(int port, String msgFrom) { this.port = port; this.msgFrom = msgFrom; try { socket = new DatagramSocket(this.port); } catch (Exception e) { e.printStackTrace(); } } public void run() { while (true) { try { byte[] buffer = new byte[1024]; DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length); socket.receive(packet); String receiveData = new String(packet.getData(), 0, packet.getData().length); System.out.println(msgFrom + ":" + receiveData); if (receiveData.equals("bye")) { break; } } catch (Exception e) { e.printStackTrace(); } } } }
- 开启学生线程
public class TalkStudent { public static void main(String[] args) { new Thread(new TalkSend(7777, "localhost", 9999)).start(); new Thread(new TalkReceive(8888, "老师")).start(); } }
- 开启老师线程
public class TalkTeacher { public static void main(String[] args) { new Thread(new TalkSend(5555, "localhost", 8888)).start(); new Thread(new TalkReceive(9999, "学生")).start(); } }
2.3 URL Demo
public class UrlDemo {
public static void main(String[] args) throws MalformedURLException {
URL url = new URL("http://localhost:8080/helloWorld/index.html?username=zhangsan&password=123456");
System.out.println("协议:" + url.getProtocol());
System.out.println("主机IP:" + url.getHost());
System.out.println("端口:" + url.getPort());
System.out.println("文件:" + url.getPath());
System.out.println("全路径:" + url.getFile());
System.out.println("参数:" + url.getQuery());
/**
* 结果
* 协议:http
* 主机IP:localhost
* 端口:8080
* 文件:/helloWorld/index.html
* 全路径:/helloWorld/index.html?username=zhangsan&password=123456
* 参数:username=zhangsan&password=123456
*/
}
}
public class UrlDown {
public static void main(String[] args) throws IOException {
// 资源路径随便改,图片视频都能下载(就是下面的文件扩展名要与之对应)
// 这是自己服务器上的一个测试文件
URL url = new URL("http://121.36.170.253:8080/mytest/Hello.txt");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
InputStream is = urlConnection.getInputStream();
// 资源输出为 1.jpg,路径默认是项目根路径(用的相对路径)
FileOutputStream fos = new FileOutputStream("1.png");
byte[] buffer = new byte[2048];
int len;
while ((len = is.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
fos.close();
is.close();
urlConnection.disconnect();
}
}