Java 网络编程入门
前言
了解Java网络编程,打好网络编程的基础。
一、TCP消息发送
1、Client
package com.xhu.java.net;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class TCPClient {
public static void main(String[] args) {
//获取本机IP地址
InetAddress clientServer = null;
Socket socket = null;
OutputStream outputStream = null;
try {
clientServer = InetAddress.getByName("127.0.0.1");
//设置一个端口号
int port = 9999;
//生成socket
socket = new Socket(clientServer, port);
//发送消息
outputStream = socket.getOutputStream();
outputStream.write("学TCP".getBytes());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//关闭socket
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
2、Server
package com.xhu.java.net;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServer {
public static void main(String[] args) {
//服务端IP+端口,即socket
ServerSocket serverSocket = null;
Socket accept = null;
InputStream is = null;
ByteArrayOutputStream baos = null;
try {
//开放端口
serverSocket = new ServerSocket(9999);
//接收客户端的连接
accept = serverSocket.accept();
//把信息读出来
is = accept.getInputStream();
//为了防止乱码,用字节数组包装流读出正确的字符
baos = new ByteArrayOutputStream();
int n = 0;
while (true) {
try {
if (!((n = is.read()) != -1)) break;
} catch (IOException e) {
e.printStackTrace();
}
baos.write(n);
}
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 (accept != null) {
try {
accept.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
二、UDP消息发送
UDP不建立连接,发完包就不管了。
package com.xhu.java.net;
import java.io.IOException;
import java.net.*;
public class UDPClient {
public static void main(String[] args) throws IOException {
//1.创建socket
DatagramSocket socket = new DatagramSocket();
//2.发送包
socket.send(new DatagramPacket("udp信息可有可无".getBytes(),
0, "udp信息可有可无".getBytes().length, InetAddress.getByName("localhost"), 9999));
//3.关闭
socket.close();
//就这样给服务端发送了,不用建立连接,发了就不管了。
}
}
package com.xhu.java.net;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UDPServer {
public static void main(String[] args) throws IOException {
//1.开放端口
DatagramSocket socket = new DatagramSocket(9999);
//2.接收包
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(packet.getAddress());
//关闭连接
socket.close();
//这是不严格的服务端,不建立连接,只有发送端和接收端。这里也可以给其它发。
}
}
三、UDP聊天
1、发送方
package com.xhu.java.net;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
public class UDPClientA {
public static void main(String[] args) throws IOException {
//1.创建socket,开放一个端口
DatagramSocket socket = new DatagramSocket(9998);
//2.发送包
//获取键盘输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String msg = br.readLine();
byte[] msgBytes = msg.getBytes();
InetAddress receive = InetAddress.getByName("localhost");
int port = 9999;
DatagramPacket packet = new DatagramPacket(msgBytes, 0, msgBytes.length, receive, port);
socket.send(packet);
if ("bye".equalsIgnoreCase(msg)) {
//关闭连接
br.close();
socket.close();
break;
}
}
//就这样给服务端发送了,不用建立连接,发了就不管了。
}
}
2、接收方
package com.xhu.java.net;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UDPClientB {
public static void main(String[] args) throws IOException {
//1.开放端口
DatagramSocket socket = new DatagramSocket(9999);
//2.接收包
while (true) {
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
//阻塞接收
socket.receive(packet);
//输出数据
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String msg = new String(packet.getData(), 0, packet.getLength());
bw.write(packet.getAddress() + ":" + msg);
bw.flush();
bw.newLine();
if ("bye".equalsIgnoreCase(msg)) {
//关闭连接
bw.close();
socket.close();
break;
}
}
//这是不严格的服务端,不建立连接,只有发送端和接收端。这里也可以给其它发。
}
}
四、多线程UDP聊天
1、ClientA
package com.xhu.java.net;
import java.io.*;
import java.net.*;
public class UDPClientA {
public static void main(String[] args) throws IOException {
//1.开放端口
DatagramSocket socket = new DatagramSocket(9998);
Send s = new Send(socket);
Receive r = new Receive(socket);
new Thread(s).start();
new Thread(r).start();
}
//发送线程
static class Send implements Runnable {
private DatagramSocket socket;
public Send(DatagramSocket socket) {
this.socket = socket;
}
@Override
public void run() {
//2.发送包
//获取键盘输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String msg = null;
try {
msg = br.readLine();
byte[] msgBytes = msg.getBytes();
InetAddress receive = InetAddress.getByName("localhost");
int port = 9999;
DatagramPacket packet = new DatagramPacket(msgBytes, 0, msgBytes.length, receive, port);
socket.send(packet);
if ("bye".equalsIgnoreCase(msg)) {
//关闭连接
br.close();
socket.close();
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//接收线程
static class Receive implements Runnable {
private DatagramSocket socket;
public Receive(DatagramSocket socket) {
this.socket = socket;
}
@Override
public void run() {
//2.接收包
while (true) {
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
//阻塞接收
try {
socket.receive(packet);
//输出数据
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String msg = new String(packet.getData(), 0, packet.getLength());
bw.write(packet.getAddress().getHostName() + ":" + String.valueOf(packet.getPort()) + ":" + msg);
bw.flush();
bw.newLine();
bw.flush();
if ("bye".equalsIgnoreCase(msg)) {
//关闭连接
bw.close();
socket.close();
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
2、ClientB
package com.xhu.java.net;
import java.io.*;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPClientB {
public static void main(String[] args) throws IOException {
//1.开放端口
DatagramSocket socket = new DatagramSocket(9999);
Send s = new Send(socket);
Receive r = new Receive(socket);
new Thread(s).start();
new Thread(r).start();
}
//发送线程
static class Send implements Runnable {
private DatagramSocket socket;
public Send(DatagramSocket socket) {
this.socket = socket;
}
@Override
public void run() {
//2.发送包
//获取键盘输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String msg = null;
try {
msg = br.readLine();
byte[] msgBytes = msg.getBytes();
InetAddress receive = InetAddress.getByName("localhost");
int port = 9998;
DatagramPacket packet = new DatagramPacket(msgBytes, 0, msgBytes.length, receive, port);
socket.send(packet);
if ("bye".equalsIgnoreCase(msg)) {
//关闭连接
br.close();
socket.close();
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//接收线程
static class Receive implements Runnable {
private DatagramSocket socket;
public Receive(DatagramSocket socket) {
this.socket = socket;
}
@Override
public void run() {
//2.接收包
while (true) {
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
//阻塞接收
try {
socket.receive(packet);
//输出数据
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String msg = new String(packet.getData(), 0, packet.getLength());
bw.write(packet.getAddress().getHostName() + ":" + String.valueOf(packet.getPort()) + ":" + msg);
bw.flush();
bw.newLine();
bw.flush();
if ("bye".equalsIgnoreCase(msg)) {
//关闭连接
bw.close();
socket.close();
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
注:
1)这里有些bug啊,比如结束时,一个线程over,应该关联另一个线程,也让它over。这里主要体现思想,能通信,仅供参考。
2)如发送、接收线程体只用写原始的两个类,可以传入socket和port来完成不同的socket的线程。
五、URL下载网络资源
package com.xhu.java.net;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
public class DownByURL {
public static void main(String[] args) {
//下载地址(下载字符)
String urlName = "https://img-baofun.zhhainiao.com/market/133/2366564fa6b83158208eb3181752a8d6_preview.mp4";//协议:/域名或IP:端口/项目/资源
InputStream is = null;
OutputStream osw = null;
try {
URL url = new URL(urlName);
//连接
HttpURLConnection uc = (HttpURLConnection) url.openConnection();
is = new BufferedInputStream(uc.getInputStream());
osw = new BufferedOutputStream(new FileOutputStream("壁纸.mp4"));
int n = 0;
while ((n = is.read()) != -1) {
osw.write(n);
}
osw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (osw != null) {
try {
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
总结
通信靠 socket,网络通信就是socket里的InputStream / OutputStream
参考文献
[1] Java 网络编程 狂神