详解UDP-TCP网络编程_udp编程实例
目录
UDP数据报套接字编程
API
代码示例--(回显)单个客户端
UdpEchoServer
UdpEchoClient
UdpDictServer(词典)
将服务端程序部署到云服务器上
TCP流套接字编程
API
长短链接
代码示例--(回显)多个客户端
TcpEchoServer
TcpEchoClient
UDP数据报套接字编程
API
DatagramSocket 是UDP Socket,用于发送和接收UDP数据报。
DatagramSocket 构造方法:
ocket 方法:
DatagramPacket是UDP Socket发送和接收的数据报。
DatagramPacket 构造方法:
DatagramPacket 方法:
构造UDP发送的数据报时,需要传入 SocketAddress ,该对象可以使用 InetSocketAddress 来创
建。
InetSocketAddress ( SocketAddress 的子类 )构造方法:
代码示例--(回显)单个客户端
UdpEchoServer
public class UdpEchoServer { //创建一个DatagramSocket对象,后续操作网卡 private DatagramSocket socket=null; public UdpEchoServer(int port) throws SocketException { socket=new DatagramSocket(port); } public void start() throws IOException { System.out.println(\"服务器启动\"); while(true){ //1.读取请求并解析 DatagramPacket requestPacket=new DatagramPacket(new byte[4096],4096); socket.receive(requestPacket); //当前完成receive之后,数据是以二进制的形式存储到DatagramPacket中了 //要想能够把这里的数据给显示出来,还需要把这个二进制数据转换成字符串 String request=new String(requestPacket.getData(),0,requestPacket.getLength()); //2.根据请求计算响应 String response=process(request); //3.把响应写回到客户端 DatagramPacket responsePacket=new DatagramPacket(response.getBytes(),response.getBytes().length, requestPacket.getSocketAddress()); socket.send(responsePacket); //4.打印 System.out.printf(\"[%s:%d] req=%s, resp=%s\\n\",requestPacket.getAddress().toString(), requestPacket.getPort(),request,response); } } public String process(String request){ return request; } public static void main(String[] args) throws IOException { UdpEchoServer server=new UdpEchoServer(9090); server.start(); }}
UdpEchoClient
public class UdpEchoClient { private DatagramSocket socket=null; private String serverIp=\"\"; private int serverPort=0; public UdpEchoClient(String ip,int port) throws SocketException { //不能指定端口 socket=new DatagramSocket(); //由于Udp自身不会持有对端的信息,就需要把对端的情况给记录下来 serverIp=ip; serverPort=port; } public void start() throws IOException { System.out.println(\"客户端启动\"); Scanner scanner=new Scanner(System.in); while(true){ System.out.print(\"->\"); String request=scanner.next(); //把请求内容构造成DatagramPacket对象,发送给服务器 DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName(serverIp),serverPort); socket.send(requestPacket); //读取响应 DatagramPacket responsePacket=new DatagramPacket(new byte[4096],4096); socket.receive(responsePacket); //把响应转换成字符串 String response=new String(responsePacket.getData(),0,responsePacket.getLength()); System.out.println(response); } } public static void main(String[] args) throws IOException {// UdpEchoClient client=new UdpEchoClient(\"127.0.0.1\",9090); UdpEchoClient client=new UdpEchoClient(\"123.249.93.104\",9090); client.start(); }}
UdpDictServer(词典)
public class UdpDictServer extends UdpEchoServer{ private Map dict=new HashMap(); public UdpDictServer(int port) throws SocketException { super(port); dict.put(\"dog\",\"小狗\"); dict.put(\"cat\",\"小猫\"); dict.put(\"pig\",\"小猪\"); } @Override public String process(String request){ return dict.getOrDefault(request,\"该词在字典中不存在\"); } public static void main(String[] args) throws IOException { UdpDictServer server=new UdpDictServer(9090); server.start(); }}
将服务端程序部署到云服务器上
打 jar 包
将生成的 jar 包上传到云服务器上,然后使用命令 java -jar netComunicate.jar
TCP流套接字编程
API
ServerSocket 是创建TCP服务端Socket的API。
ServerSocket 构造方法:
ServerSocket 方法:
Socket 是客户端Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回。
不管是客户端还是服务端Socket,都是双方建立连接以后,保存的对端信息,及用来与对方收发数据的。
Socket 构造方法:
:
长短链接
TCP发送数据时,需要先建立连接,什么时候关闭连接就决定是短连接还是长连接:
短连接:每次接收到数据并返回响应后,都关闭连接,即是短连接。也就是说,短连接只能一次收发数据。
长连接:不关闭连接,一直保持连接状态,双方不停的收发数据,即是长连接。也就是说,长连接可以多次收发数据。
对比以上长短连接,两者区别如下:
建立连接、关闭连接的耗时:短连接每次请求、响应都需要建立连接,关闭连接;而长连接只需要第一次建立连接,之后的请求、响应都可以直接传输。相对来说建立连接,关闭连接也是要耗时的,长连接效率更高。
主动发送请求不同:短连接一般是客户端主动向服务端发送请求;而长连接可以是客户端主动发送请求,也可以是服务端主动发。
两者的使用场景有不同:短连接适用于客户端请求频率不高的场景,如浏览网页等。长连接适用于客户端与服务端通信频繁的场景,如聊天室,实时游戏等。
代码示例--(回显)多个客户端
TcpEchoServer
public class TcpEchoServer { private ServerSocket serverSocket=null; public TcpEchoServer(int port) throws IOException { serverSocket=new ServerSocket(port); } public void start() throws IOException { System.out.println(\"服务器启动!\"); ExecutorService service= Executors.newCachedThreadPool(); while(true){ //通过accept方法,把内核中已经建立好的连接拿到应用程序中 Socket clientSocket=serverSocket.accept();// Thread t=new Thread(()->{// processConnection(clientSocket);// });// t.start(); service.submit(new Runnable() { @Override public void run() { processConnection(clientSocket); } }); } } public void processConnection(Socket clientSocket){ System.out.printf(\"[%s:%d] 客户端上线!\\n\",clientSocket.getInetAddress(),clientSocket.getPort()); try(InputStream inputStream=clientSocket.getInputStream(); OutputStream outputStream=clientSocket.getOutputStream()) { //使用 try() 方式,避免后续用完了流对象,忘记关闭 while(true){ Scanner scanner=new Scanner(inputStream); if(!scanner.hasNext()){ System.out.printf(\"[%s:%d] 客户端下线!\\n\",clientSocket.getInetAddress(),clientSocket.getPort()); break; } //1.读取请求并解析,此处就以 next 作为读取请求的方法,next的规则就是读到\"空白符\"就返回 String request=scanner.next(); //2.根据请求,计算响应 String response=process(request); //3.把响应写回客户端 // 可以把String 转换成字节数组,写入到OutputStream // 也可以使用PrintWriter把OutputStream包裹一下,来写入字符串 PrintWriter printWriter=new PrintWriter(outputStream); // 此处的println不是打印到控制台了,而是写入到outputStream对应的流对象中 // 也就是写入到clientSocket里面,自然这个数据也就通过网络发送出去了 // 此处使用println带有 \\n 也是为了后续客户端这边可以使用 scanner.next来读取数据 printWriter.println(response); // 此处还应该 刷新缓冲区,如果没有刷新缓冲区,可能数据仍然在内存中,没有被写入网卡 printWriter.flush(); //4.打印一下这次请求交互过程的内容 System.out.printf(\"[%s:%d] req=%s, resp=%s\\n\",clientSocket.getInetAddress(),clientSocket.getPort(), request,response); } } catch (IOException e) {// throw new RuntimeException(e); e.printStackTrace(); }finally { try{ //在这个地方进行clientSocket的关闭 //processConnection就是在处理一个链接,这个方法这行完毕,这个链接也就处理完了 clientSocket.close(); } catch (IOException e) { throw new RuntimeException(e); } } } public String process(String request){ return request; } public static void main(String[] args) throws IOException { TcpEchoServer server=new TcpEchoServer(9090); server.start(); }}
TcpEchoClient
public class TcpEchoClient { private Socket socket=null; public TcpEchoClient(String serverIp,int serverPort) throws IOException { socket=new Socket(serverIp,serverPort); } public void start(){ Scanner scanner=new Scanner(System.in); try(InputStream inputStream=socket.getInputStream(); OutputStream outputStream=socket.getOutputStream()){ PrintWriter writer=new PrintWriter(outputStream); Scanner scannerNetwork=new Scanner(inputStream); while(true){ System.out.print(\"->\"); String request=scanner.next(); // 这里使用 println 是为了让请求后面带上换行 // 也就是和服务器读取请求 sacnner.next呼应 writer.println(request); writer.flush(); String response=scannerNetwork.next(); System.out.println(response); } } catch (IOException e) { throw new RuntimeException(e); } } public static void main(String[] args) throws IOException { TcpEchoClient client=new TcpEchoClient(\"127.0.0.1\",9090); client.start(); }}