网络通信三要素
IP:设备在网络中的地址,也是唯一标识。
端口:应用在设备中的唯一标识。
协议:连接和数据在网络中传输的规则。
·IP
java中的IP类
·端口
·协议
TCP和UDP
:传输层协议,编程中使用的主要传输协议。
- UDP协议:无连接,不可靠通信。
- TCP通信:面向连接,可靠通信。
三次握手,四次挥手。相对没有udp效率高
传输时也会返回确认,确保可靠性。
java中使用UDP
只要时DatagramSocket
对象都使用UDP建立连接
DatagramSocket
用来创建客户端服务端,DatagramPacket
用来创建数据包,数据传输时都发送数据包。
客户端发送数据
public class Main {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
DatagramSocket socket = new DatagramSocket();
byte[] bytes = sc.nextLine().getBytes();
DatagramPacket packet = new DatagramPacket(bytes,bytes.length,InetAddress.getLocalHost(),8800);
socket.send(packet);
System.out.println("发送完毕");
socket.close();
}
}
服务端接收数据
public class server {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(8800);
byte[] buffer = new byte[1024 * 64];
DatagramPacket packet = new DatagramPacket(buffer,buffer.length);
socket.receive(packet);
int length = packet.getLength();
System.out.println(new String(buffer, 0, length));
}
}
允许客户端多开
可以实现多发多收,此时不能指定端口,自动分配才不会冲突。
JAVA中使用TCP
使用Socket
类即为TCP协议通信。
ServerSocket
类用来建立服务端的TCP连接
通过accept方法获得服务端的socket对象以后就可以使用socket进行数据通信了。
使用DataInputStream
和DataOutputStream
进行通信数据传输比较好用。
读写时客户端和服务端用的数据类型和读写方法都要一一对应。
客户端代码
public class client {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
try(Socket socket = new Socket("localhost",8888);
DataOutputStream output = new DataOutputStream(socket.getOutputStream());) {
while (true) {
System.out.println("talk:");
output.writeUTF(sc.nextLine());
output.flush();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
服务端代码
public class server {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8888);
while (true) {
Socket socket = serverSocket.accept();
new ServerReaderTheard(socket).start();
}
}
}
public class ServerReaderTheard extends Thread{
private Socket socket;
public ServerReaderTheard(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try(DataInputStream input = new DataInputStream(socket.getInputStream());) {
while (true) {
try {
System.out.println(socket.getRemoteSocketAddress());
System.out.println(input.readUTF());
} catch (IOException e) {
System.out.println(socket.getRemoteSocketAddress()+"离线了");
input.close();
socket.close();
break;
}
}
} catch (IOException e) {
}
}
}
通过创建线程实现多客户端同时通信。
实现简易B/S架构
public class server {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8888);
while (true) {
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress()+ "在线");
new ServerReaderTheard(socket).start();
}
}
}
public class ServerReaderTheard extends Thread{
private Socket socket;
public ServerReaderTheard(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try(DataInputStream input = new DataInputStream(socket.getInputStream());
PrintStream output = new PrintStream(socket.getOutputStream())) {
output.println("HTTP/1.1 200 OK");
output.println("Content-type:text/html;charset=UTF-8");
output.println();
output.println("你好");
} catch (IOException e) {
}
}
}
- 每次都创建新线程,使用线程池优化一下
public class server {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8888);
ThreadPoolExecutor pool = new ThreadPoolExecutor(16,16,0, TimeUnit.SECONDS,new ArrayBlockingQueue<>(8),
Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
while (true) {
Socket socket = serverSocket.accept();
pool.execute(new ServerReaderTheard(socket));//传的是Runnable对象
System.out.println(socket.getRemoteSocketAddress()+ "在线");
new ServerReaderTheard(socket).start();
}
}
}