UDP篇:UDP是不可靠传输
客户端配置
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws IOException {
System.out.println("客户端启动");
DatagramSocket socket = new DatagramSocket();
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入:");
String s = sc.nextLine();
if ("exit".equals(s)) {
break;
}
byte[] bytes = s.getBytes();
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getLocalHost(), 6666);
socket.send(packet);
}
System.out.println("数据包发送完毕");
socket.close();
}
}
使用DatagramSocket方法建立连接,不写参数将随机分配一个端口用于传输数据到服务器,添加参数可以指定端口用于传输,但指定端口进行多发多收会提示端口已被占用。
用byte字节进行传输,分包进行数据传输,用DatagramPacket来对数据进行包装,参数列表分别为1.字节串数据变量名 2.字节串长度 3.服务器ip地址 4.服务器端口号
客户端传输完毕数据记得需要关闭socket,至此UDP客户端已结束
服务端配置
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class Server {
public static void main(String[] args) throws IOException {
System.out.println("服务端启动");
DatagramSocket socket = new DatagramSocket(6666);
byte[] buf = new byte[1024 * 64];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
while (true) {
socket.receive(packet);
String message = new String(buf, 0, packet.getLength());
System.out.println(message);
}
}
}
服务器端也需要用DatagramSocket方法来建立socket,并指定端口,用于客户端来传递数据。当然服务端也是使用byte字节来接收数据,而且接收的包大小最大为64kb,所以尽量将byte数组长度定位byte[1024* 64],这样可以保证数据不会溢出,由于UDP是不可靠传输,所以即便丢包也会不会有任何反馈。服务端packet可以记录传输的包的大小,所以读取时可以不读超出的数组长度。
运行时,先运行服务端,再运行客户端
这种不可靠传输经常用于视频语音电话和直播,即便丢失几个包影响也不大,效率很高
TCP:可靠传输
客户端配置
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
Scanner sc = new Scanner(System.in);
OutputStream os = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
while(true){
String s = sc.nextLine();
if("exit".equals(s)){
dos.close();
socket.close();
break;
}
dos.writeUTF(s);
dos.flush();
}
}
}
客户端用Socket方法建立Socket,参数列表为目的主机ip地址和端口号。TCP用字节流进行数据传输,在这里我将数据流包装为高级流DataOutputStream(看了一个视频,他们说用过各种高级流,发现这个高级流适合Socket进行数据传输),和UDP一样,传输结束需要关闭socket,在TCP中还需要关闭流。输出流中需要flush来进行一下刷新,防止流的缓存仍存在本机中,来将它刷新出去。
服务端配置
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
System.out.println("服务端已启动");
ServerSocket serverSocket = new ServerSocket(8888);
while(true){
Socket socket = serverSocket.accept();
new ServerReaderThread(socket).start();
}
}
}
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.Socket;
public class ServerReaderThread extends Thread{
private Socket socket;
public ServerReaderThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
System.out.println(socket.getRemoteSocketAddress() + "已加入连接");
InputStream is = socket.getInputStream();
DataInputStream dis = new DataInputStream(is);
while(true){
try {
System.out.println(dis.readUTF());
} catch (Exception e) {
socket.close();
dis.close();
System.out.println(socket.getRemoteSocketAddress() + "断开连接");
break;
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
由于TCP正常只能进行一对一通信,在当前结束通信后才能让下一个主机进行通信,所以为了实现多发多收,用多线程,将每一个主机分一个单独的线程给他同时进行和服务端进行通信。
客户端用什么流进行的传输,服务端也要用什么流来进行接收,也要用同样的读取方法。
当客户端断开连接,服务端没有收到通知会抛出异常,所以在服务端的等待窗口添加异常处理,当客户端断开连接,服务端也可以在异常处理提示客户端已经断开连接。