利用tcp,udp套接字分别写一个简单的回显程序

UDP:

准备工作:udp套接字认识

DatagramSocket:

DatagramSocket是Java中用于实现UDP协议的套接字类。它提供了在网络上发送和接收UDP数据报的功能。

方法:

DatagramPacket

DatagramPacket是Java中用于表示UDP数据报的类。它封装了一个数据报(Datagram)以及该数据报的目标地址、目标端口号等信息。通过DatagramPacket可以实现在网络上发送和接收UDP数据报。

方法:

另外客户端在输入ip时要构建成一个InetAddress对象来表示ip

这里只介绍了实现回显程序所需要的方法。

实现回显程序:

实现服务端:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class Sever2 {
    private DatagramSocket datagramSocket;

    public Sever2(int port) throws SocketException {
        //服务器端口号需要固定,这里指定服务器端口号
        datagramSocket = new DatagramSocket(port);
    }
    //处理请求
    //这里我们是一个回显程序,所以不进行处理,直接返回
    public String process(String s) {
        return s;
    }
    public void start() throws IOException {
        System.out.println("服务器启动");
        while(true) {
            //构建请求数据报
            DatagramPacket requestPacket = new DatagramPacket(new byte[2000],2000);
            //接收客户端的请求数据报
            //如果请求还没有接收到,就一直阻塞等待
            datagramSocket.receive(requestPacket);
            //转化成字符串并进行处理
            //这样的转字符串的前提是, 后续客户端发的数据就是一个文本的字符串.
            String request = new String(requestPacket.getData(),0,requestPacket.getLength());
            //处理请求
            String respond = process(request);
            //处理完毕,构建返回数据报
            //从请求数据报中获取客户端的端口和ip地址
            DatagramPacket respondPacket =
                    new DatagramPacket(respond.getBytes(),respond.getBytes().length,requestPacket.getSocketAddress());
            //向客户端返回数据报
            datagramSocket.send(respondPacket);

            System.out.printf("[%s:%d] req: %s, resp: %s\n", respondPacket.getAddress().toString(), respondPacket.getPort(),
                    request, respond);

        }
    }

    public static void main(String[] args) throws IOException {
        Sever2 sever2 = new Sever2(2030);
        sever2.start();
    }
}

实现客户端

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class Client2 {
    //服务器端口号
    private int port;
    //服务器ip:
    private  String ip;

    private DatagramSocket datagramSocket;

    public Client2(int port, String ip) throws SocketException {
        this.port = port;
        this.ip = ip;
        //创建套接字对象:客户端端口由系统随机分配
        datagramSocket = new DatagramSocket();
    }
    public void start() throws IOException {
        Scanner scan = new Scanner(System.in);
        System.out.println("客户端启动");
        while(true) {
            //提示用户输入数据
            System.out.println("->");
            String requet = scan.next();
            //构建udp发送数据报
            DatagramPacket requestPacket =
                    new DatagramPacket(requet.getBytes(),requet.getBytes().length, InetAddress.getByName(ip),port);
            //向服务器发送待处理数据报
            datagramSocket.send(requestPacket);
            //构建啊udp接收数据报
            DatagramPacket reponsePacket = new DatagramPacket(new byte[2000] , 2000);
            //这里reponsePacket是一个接收型参数
            datagramSocket.receive(reponsePacket);
            //利用String构造方法将数据报转化成一个字符串
            String reponse = new String(reponsePacket.getData(),0,reponsePacket.getLength());
            System.out.println(reponse);
        }
    }

    public static void main(String[] args) throws IOException {
        //指定服务器端口,ip地址为环回地址
        Client2 client2 = new Client2(2030,"127.0.0.1");
        client2.start();
    }
}

效果:

TCP:

准备工作:tcp套接字认识

ServerSocket

Socket

ServerSocket是服务器端套接字,用于监听客户端的连接请求。一旦有客户端连接请求到达,ServerSocket就会通过accept方法来获取到这个请求并创建一个Socket对象进行描述然后决定是否建立连接。

Socket是客户端套接字,用于与服务器进行通信。一旦连接建立成功,服务器和客户端就可以利用Socket通过输入输出流进行通信。

实现回显程序

实现服务端

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TcpSever2 {
    //这里使用线程池来实现多个客户端共同访问服务器的并发场景
    private ExecutorService pool = Executors.newCachedThreadPool();
    private ServerSocket serverSocket = null;
    //创建服务器端套接字并指定端口
    public TcpSever2(int port) throws IOException {
        serverSocket = new ServerSocket(port);
    }
    public void start() throws IOException {
        System.out.println("服务器上线");
        while(true) {
            //监听客户端的连接请求,并通过accept方法获取到这个请求,并创建一个Socket来描述这个请求
            Socket socket = serverSocket.accept();
            //processConnection(socket);
            //线程池来处理并发的连接请求
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    processConnection(socket);
                }
            });
        }

    }
    //请求的处理
    public void processConnection(Socket socket) {
        //打印客户端信息
        System.out.printf("客户端:[ip:%s|port:%d]\n",socket.getInetAddress().toString(),socket.getPort());
        //通过流对象进行通信
            try(InputStream inputStream = socket.getInputStream();
                OutputStream outputStream = socket.getOutputStream()) {
                while(true) {
                    //获取流对象信息
                    Scanner scan = new Scanner(inputStream);
                    if(!scan.hasNext()) {
                        System.out.println("客户端下线");
                        System.out.printf("客户端:[ip:%s|port:%d]\n",socket.getInetAddress().toString(),socket.getPort());
                    }
                    String request = scan.next();
                    //按照程序逻辑处理请求信息,这里由于是回显程序,所以直接返回即可
                    String respond = process(request);
                    //将处理好的信息输入到流对象中
                    PrintWriter printWriter = new PrintWriter(outputStream);
                    printWriter.println(respond);
                    //为什么进行flush
                    //pritWriter内置了一个缓冲区
                    //flush确保缓冲区中的所有数据都被写入到输出流中,
                    printWriter.flush();
                    System.out.printf("[ip:%s|port:%d],req:%s,rep:%s\n",socket.getInetAddress().toString(),socket.getPort(),request,respond);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                //高并发场景,可能会建立很多个socket,如果不关闭就会造成文件资源泄露
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
    }
    public String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        TcpSever2 tcpSever2 = new TcpSever2(8086);
        tcpSever2.start();

    }

}

实现客户端

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class TcpClint2 {
    private Socket socket = null;
    //指定socket发起连接的目标的ip和端口
    public TcpClint2(String ip,int port) throws IOException {
        socket = new Socket(ip , port);
    }
    public void start() {
        Scanner scan = new Scanner(System.in);
        System.out.println("客户端上线");
            try(InputStream inputStream = socket.getInputStream();
                OutputStream outputStream = socket.getOutputStream()){
                while(true){
                    //控制台输入提示符
                    System.out.println(">");
                    String request = scan.next();
                    //将请求处理的信息输入到流对象当中
                    PrintWriter printWriter = new PrintWriter(outputStream);
                    printWriter.println(request);
                    //为什么进行flush
                    //pritWriter内置了一个缓冲区
                    //flush确保缓冲区中的所有数据都被写入到输出流中,
                    printWriter.flush();

                    //从流中获取处理完的信息
                    Scanner scanResponse = new Scanner(inputStream);
                    String response = scanResponse.next();
                    System.out.println(response);
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    public static void main(String[] args) throws IOException {
        TcpClint2 tcpClint2 = new TcpClint2("127.0.0.1",8086);
        tcpClint2.start();
    }
}

效果:

注意的点:

1.printWriter像流中输出了信息后,最好调用flush方法刷新一下,确保缓冲区中的所有数据都被写入到输出流中。

2.客户端与服务器端相互配合:比如:客户端在写入请求时,使用println,服务器端在读取请求时就用next();

3.并发场景下注意一定要关闭涉及到打开文件的操作,比如这里的Socket,流对象,以防止发生文件资源泄漏的情况

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值