网络编程
三要素:协议、IP地址、端口号
TCP
TCP是一个面向连接的通信协议,需要完成“三次握手”才能通信
套接字socket使用
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Create by xiye on 2019/12/6 14:40
*/
public class Server {
/*
* 服务端使用ServerSocket
* */
public static void main(String[] args) throws IOException {
// 设置一个监听端口,供客户端访问
ServerSocket socket = new ServerSocket(1314);
System.out.println("服务已开启...");
Socket server = socket.accept(); // 阻塞,等待客户端接收
String host = getHost(server);
// 获取客户端请求内容
InputStream is = server.getInputStream();
byte[] b = new byte[128];
int len = is.read(b);
String req = new String(b, 0, len);
System.out.println(host + ":" + req);
// 返回信息
OutputStream os = server.getOutputStream();
os.write(req.getBytes());
os.close();
is.close();
server.close();
}
/**
* 获取IP地址和端口号拼接字符串
* @param socket 套接字对象
* @return IP地址:端口
*/
private static String getHost(Socket socket) {
return socket.getInetAddress().getHostAddress() + ":" + socket.getPort();
}
}
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
/**
* Create by xiye on 2019/12/6 14:43
*/
public class Client {
/*
* 客户端使用Socket
* */
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(System.in);
// 连接服务端IP和端口
Socket client = new Socket("192.168.31.103", 1314);
// String str = "Nice to meet you~^_^~";
String str = sc.next();
OutputStream os = client.getOutputStream();
// 发送
os.write(str.getBytes());
// 接收回返消息
InputStream is = client.getInputStream();
if (is != null) {
String host = getHost(client);
byte[] b = new byte[128];
int len = is.read(b);
System.out.print(host + "回复您:" + new String(b, 0, len));
}
is.close();
os.close();
client.close();
sc.close();
}
/**
* 获取IP地址和端口号拼接字符串
* @param socket 套接字对象
* @return IP地址:端口
*/
private static String getHost(Socket socket) {
return socket.getInetAddress().getHostAddress() + ":" + socket.getPort();
}
}
TCP单一聊天实现
服务端
package com.xiye.single;
import com.xiye.single.thread.Receive;
import com.xiye.single.thread.Send;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Create by xiye on 2019/12/6 16:42
*/
public class ServerTCP {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(1314);
System.out.println("服务端开启....");
Socket socket = serverSocket.accept();
new Thread(new Receive(socket)).start();
new Thread(new Send(socket)).start();
}
}
客户端
package com.xiye.single;
import com.xiye.single.thread.Receive;
import com.xiye.single.thread.Send;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Create by xiye on 2019/12/6 16:42
*/
public class ClientTCP {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("192.168.31.103", 1314);
new Thread(new Receive(socket)).start();
new Thread(new Send(socket)).start();
}
}
发送线程
package com.xiye.single.thread;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
/**
* Create by xiye on 2019/12/6 16:42
*/
public class Send implements Runnable {
private Socket socket;
public Send(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
while (true) {
synchronized (this) {
if (socket != null) {
Scanner sc = new Scanner(System.in);
System.out.print("聊天内容:");
try {
OutputStream os = socket.getOutputStream();
os.write(sc.nextLine().getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
private static String getHost(Socket socket) {
return socket.getInetAddress().getHostAddress() + ":" + socket.getPort();
}
}
接收线程
package com.xiye.single.thread;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
/**
* Create by xiye on 2019/12/6 16:42
*/
public class Receive implements Runnable {
private Socket socket;
public Receive(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
while (true) {
synchronized (this) {
if (socket != null) {
try {
InputStream is = socket.getInputStream();
byte[] bytes = new byte[256];
int len = is.read(bytes);
System.out.println("收到" + getHost(socket) + "信息:" + new String(bytes, 0, len));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
private static String getHost(Socket socket) {
return socket.getInetAddress().getHostAddress() + ":" + socket.getPort();
}
}
上传下载
TCP上传文件
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
/**
* Create by xiye on 2019/12/9 10:31
*/
public class Demo2_shutdown {
/*
* 输入输出流关闭,socket也会关闭,意味着后面无法操作socket
* 使用while循环读取/写入到服务端时,如果客户端没有“关闭”,服务端会一直等待,意味着没有读取。
* 所以客户端需要“关闭”流,避免socket被关闭,导致后面无法再操作socket,不要直接关闭流(即XX.close()),
* 可以使用socket.shutdownOutput()、shutdownInput()“关闭”,提醒服务端客户端已经输出/输入完成
* */
public static class TCPServer {
public static void main(String[] args) throws IOException {
// 服务端
ServerSocket serverSocket = new ServerSocket(1314);
while (true) {
Socket socket = serverSocket.accept();
new Thread(() -> {
try {
// 获取客户端上传文件并保存
InputStream is = socket.getInputStream();
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("Day20/upload/" + getDataTime() + ".png"));
byte[] data = new byte[4 * 1024];
int len;
while ((len = is.read(data)) != -1) {
bos.write(data, 0, len);
bos.flush(); // 字符流、缓冲流使用有效,字节流无效
}
// 针对socket是什么流,就关闭什么
socket.shutdownInput(); // "关闭"输入流,不关无法对写入的文件进行操作,如删除
// 返回信息给客户端
OutputStream os = socket.getOutputStream();
os.write("上传成功".getBytes());
os.close();
bos.close();
is.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
}
public static class TCPClient {
// 客户端
public static void main(String[] args) throws IOException {
for (int i = 0; i < 8; i++) {
Socket socket = new Socket("localhost", 1314);
new Thread(() -> {
try {
// 读取需要上传的文件
// 直接用FileInputStream也可以
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:/file_test/test.png"));
OutputStream os = socket.getOutputStream();
byte[] data = new byte[4 * 1024];
int len;
while ((len = bis.read(data)) != -1) {
os.write(data, 0, len);
}
// 不关闭socket的输出流,服务端while循环读取时,永远不会为-1,即一直在等待读取
//os.close();// 如果此处直接关闭,会连同socket一起关闭,下面再操作socket出现异常:Exception in thread "main" java.net.SocketException: Socket is closed
socket.shutdownOutput(); // 关闭输出流,形如:通知服务端,客户端已完成文件地传输
// 获取服务端返回信息
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String result = br.readLine();
System.out.println(result);
br.close();
os.close();
bis.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private static String getDataTime() {
DateFormat format = new SimpleDateFormat("yyyyMMddHHmmssSS");
return format.format(System.currentTimeMillis());
}
}
TCP下载文件
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
/**
* Create by xiye on 2019/12/9 15:10
*/
public class Demo3_download {
private static String uploadPath = "Day20/upload/";
public static class TCPServer {
public static void main(String[] args) throws IOException {
// 服务端
ServerSocket serverSocket = new ServerSocket(1314);
while (true) {
Socket socket = serverSocket.accept();
new Thread(() -> {
try {
// 获取客户端请求下载文件名
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String fileName = br.readLine();
socket.shutdownInput(); // 不关闭时,客户端和服务端一直等待
System.out.println(getHost(socket) + "请求下载:" + fileName);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(uploadPath + fileName));
OutputStream os = socket.getOutputStream();
byte[] data = new byte[4 * 1024];
int len;
while ((len = bis.read(data)) != -1) {
os.write(data, 0, len);
}
//socket.shutdownOutput();
os.close();
bis.close();
br.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
}
public static class TCPClient {
// 客户端
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(System.in);
// 显示列表
System.out.println("=================Download images============");
for (File f : new File(uploadPath).listFiles()) {
System.out.println(f.getName());
}
//for (int i = 0; i < 8; i++) {
Socket socket = new Socket("localhost", 1314);
new Thread(() -> {
try {
// 请求下载文件
System.out.println("------------------");
String fileName = sc.nextLine();
OutputStream os = socket.getOutputStream();
os.write(fileName.getBytes());
socket.shutdownOutput(); // 不关闭,客户端一直等待
// 下载文件
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("Day20/download/" + fileName));
byte[] data = new byte[4 * 1024];
int len;
while ((len = bis.read(data)) != -1) {
bos.write(data, 0, len);
bos.flush(); // 不写似乎也行
}
bos.close();
bis.close();
os.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//}
}
}
private static String getHost(Socket socket) {
return socket.getInetAddress().getHostAddress() + ":" + socket.getPort();
}
}
UDP
- UDP是一个面向无连接的通信协议,不安全,容易丢包
package com.xiye.single;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.Arrays;
/**
* Create by xiye on 2019/12/6 18:31
*/
public class ServerUDP {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(1314);
while (true) {
byte[] bytes = new byte[256];
// 获取客户端请求信息
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
socket.receive(packet); // 阻塞
System.out.println(new String(packet.getData(), 0, packet.getLength()));
// 返回信息
byte[] b = new byte[packet.getLength()];
System.arraycopy(packet.getData(), 0, b, 0, packet.getLength());
System.out.println(getHost(packet) + ":" + Arrays.toString(b));
packet.setData(b);
socket.send(packet);
}
}
private static String getHost(DatagramPacket packet) {
return packet.getAddress().getHostAddress() + ":" + packet.getPort();
}
}
package com.xiye.single;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* Create by xiye on 2019/12/6 18:31
*/
public class ClientUDP {
public static void main(String[] args) throws IOException {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
try {
new ClientUDP();
//Thread.sleep(500);
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
public ClientUDP() throws IOException {
DatagramSocket socket = new DatagramSocket();
byte[] bytes = "使用UDP数据包传输".getBytes();
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.31.103"), 1314);
socket.send(packet);
// 获取回返信息
byte[] b = new byte[packet.getLength()];
DatagramPacket dp = new DatagramPacket(packet.getData(), packet.getLength());
socket.receive(dp);
System.out.println("收到" + getHost(dp) + "返回信息:" + new String(dp.getData(), 0, dp.getLength()));
}
private static String getHost(DatagramPacket packet) {
return packet.getAddress().getHostAddress() + ":" + packet.getPort();
}
}