0


基于TCP与UDP网络编程

一.什么是TCP与UDP

TCP与UDP是计算机网络中五层模型的运输层协议。

TCP 协议:是传输控制协议,它是面向连接的协议,支持可靠传输和双向通信。它在传输数据之前需要先建立连接,建立连接后才能传输数据,传输完后还需要断开连接。TCP协议之所以能保证数据的可靠传输,是通过接收确认、超时重传这些机制实现的。并且,TCP协议允许双向通信,即通信双方可以同时发送和接收数据。

UDP协议:(User Datagram Protocol)是一-种数据报文协议,它是无连接协议,不保证可 靠传输。 因为UDP协议在通信前不需要建立连接,因此它的传输效率比TCP高,而且UDP 协议比TCP协议要简 单得多

二.什么是Socket

    在我们进行网络编程时,都会接触到一个名叫scoket的概念,应用程序通过Scoket来建立远程连接,Socket通过内部封装好的协议把数据传输到网络。

    为什么需要Socket 进行网络通信?因为仅仅通过IP地址进行通信是不够的,同一台计算机同- -时间会运行多个网络应用程序,例如浏览器、QQ、邮件客户端等。当操作系统接收到一个数据包的时候,如果 只有IP地址,它没法判断应该发给哪个应用程序,所以,操作系统抽象出Socket 接口,每个应用程序需 要各自对应到不同的Socket,数据包才能根据 Socket正确地发到对应的应用程序。

    使用Socket进行网络编程时,本质上就是两个进程之间的网络通信。其中一个进程必须充当服务器端,它会主动监听某个指定的端口,另一个进程必须充当客户端,它必须主动连接服务器的IP地址和指定端口,如果连接成功,服务器端和客户端就成功地建立了一个TCP连接,双方后续就可以随时发送和接收,因此,当Socket 连接成功地在服务器端和客户端之间建立后:对服务器端来说,它的Socket是指定的IP地址和指定的端口号。

三.TCP网络编程简单实现

    TCP的编程实现客户端与服务器端交互,是通过建立连接,从而利用“流”来进行数据交换的,即使用字节输入/输出流,把要发送的数据,存储到字节数组,通过“流”来实现发送与接收。

接下来我们以客户端向服务器端上传图片的简单例子来说明TCP编程。

1.建立服务器端

第一步:建立socket,服务器端使用java提供的ServerSocket创建于客户端交互的对象,并且监听指定端口。

第二步:建立与客户端的连接,创建一个Scoket,调用accept()方法,与客户端建立连接,并且获取客户端的IP地址

第三步:创建输入流,来读取客户端上传的照片使用:getInputStream()

第四步:创建输出流,对客户端上传的图片,写入到本地,我们这里使用BufferedInputStream来实现建立字节字节数组对传过来的数据进行批量写入。

第六步:当我们成功接收到客户端上传的图片以后,要给客户端发送一个反馈,这时,我们需要创建一个输出流,向客户端进行反馈。

完整的实例代码如下:

try {
            //ServerSocket:服务器端进行通信的对象
            ServerSocket server = new ServerSocket(8848);
            
            //死循环:不断接收客户端的连接
            while(true) {
                
                //服务器进入“等待”状态
                //如果有客户端连接时,该方法1返回客户端的Socket
                Socket cilent = server.accept();
                InetAddress clientNetAddress = cilent.getInetAddress();
                System.out.println("客户端" +clientNetAddress + "正在连接.......");
            
                // 接收来自客户端上传的图片
                // 输入流:读取来自客户端发送的图片文件流
                // 输出流:写入本地图片
                String imgName = clientNetAddress.getHostAddress().replaceAll("\\.", "\\-") + ".jpg";

                try(InputStream in = cilent.getInputStream();
                    BufferedInputStream bis = new BufferedInputStream(in);
                    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:\\test\\aaa\\" + imgName))){
                
                    // 每次读取来自客户端的图片文件流
                    // 写入本地
                    byte[] buff = new byte[1024];
                        
                    int len = -1;
                
                    while((len = bis.read(buff)) != -1) {
                            
                        bos.write(buff,0,len);
                     }
                    
                    System.out.println("图片读取完毕!");
                    
                    // 输出提示信息 => 客户端
                    try(BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(cilent.getOutputStream()));){
                    
                        writer.write("上传完毕!");
                        writer.newLine();
                    }    
                }
          }
            
      } catch (IOException e) {
                             
        e.printStackTrace();
    }

我们这里用到了一个死循环,是为了保证服务器端可以持续不断地接收来自客户端上传的图片。

2.建立客户端

相比服务器端,客户端就简单很多

第一步:创建Socket,用于和服务器端进行连接的组件,传入服务器端的IP地址与端口号。

第二步:创建一个输出流,将要上传的图片发送至服务器端。

第三步:创建输入流,来获取将要发送的本地的图片的路径,我们这里也使用BufferedInputStream来对本地图片进行一个批量读取,将读取到的内容发送至服务器端。

这里值得注意的是:使用cilent.shutdownOutput(),输出暂时结束(Socket没有关闭)

第四步:我们等待服务器端接收成功后,发生给我们一个反馈,我们需要创建一个Socket的输入流,来接收服务器端对我们的反馈。

基本实现代码如下:

//Socket:客户端进行通讯的组件
        //本地图片获取 = > 通过输出流,发送(输出)至服务器
        //OutputStream:输出流,读取到本地图片文件流,发送(输出)至服务器
        //BufferedInputStream:输入流,读取本地文件
        
        try (
         Socket cilent = new Socket("192.168.254.188",8848);
                OutputStream out = cilent.getOutputStream();
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\数据分析\\2017年第一季度各产业生产总值占比饼图.png"))) {
            
            //每次读取到1024字节
            byte[] buff = new byte[1024];
            int len = -1;
            
            while((len = bis.read(buff)) != -1) {
                //将读取到的内容,通过输出流发送至服务器
                out.write(buff);    
            }
            
            //输出暂时结束(Socket没有关闭)
            cilent.shutdownOutput();
            
            //读取来自服务器的反馈
            try(BufferedReader reader = new BufferedReader(new InputStreamReader(cilent.getInputStream()));){
                String  reply = reader.readLine();
                System.out.println("服务器的反馈:" + reply);
            }
            
        } catch (IOException e) {
            
            e.printStackTrace();
        }

四.UDP网络编程简单实现

UDP和TCP相比,就简单的多,因为UDP不需要建立连接,也就没有区分哪一个是客户端哪一个是服务器端,是依靠数据包来进行实现的,数据包也是收一个发一个,不存在使用流的概念。

UDP也是需要使用Socket来监听端口的的,不过它使用的是java提供的DatagramSocket。

我们以一个简易的聊天室的案例,来实现简单的UDP编程:

第一步:创建Scanner 来进行对话的输入

第二步:创建Socket,来监听端口。

第三步:创建两个数据包来实现对话的发送与接收。

1.发送:

这里使用的是DatagramPacket,传入一个字节数组,并且传入将要发送的IP地址与端口号

使用socket.send(sendPacket),来进行发送

    try (DatagramSocket socket = new DatagramSocket(6666);) {
        
            //提前创建两个Packet数据包,分别用于发送和接收
            DatagramPacket sendPacket = 
                    new DatagramPacket(
                        new byte[1024],1024, //数据
                        new InetSocketAddress("192.168.254.153",7788)  //目的地
                                        );
            
            while(true) {
                //发送
                System.out.print("你说:");
                String sendContent = input.nextLine();
                
                sendPacket.setData(sendContent.getBytes());
                socket.send(sendPacket1);

                if(sendContent.equals("滚")) {
                    System.out.println("我不想跟你讲话");
                    return;
                }
                socket.send(sendPacket);

sendPacket.setData(sendContent.getBytes())

是将输入的数据存入数据包中

2.接收

首先建立一个接收的数据包,传入一个自定义的字节数组,用来接收数据

DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);

使用socket.receive(receivePacket),方法来进行数据包的接收

由于接收到的是一个数据包,我们如果想正常显示,就要把它变成字符串

//packet.getData():获取数据包中的“数据”(字节数组)
//packet.getOffset():获取数据包中的“读取位置”
//packet.getLength():获取数据包中的“长度”

String receiveContent = new String(receivePacket.getData(),receivePacket.getOffset(),receivePacket.getLength());

当我们想要不停地与对方进行聊天时,就可以写一个死循环while(true){},来一直输入内容,直到输入关键字,程序才会退出。

代码实现:

//接收
socket.receive(receivePacket);
String receiveContent = new String(receivePacket.getData(),receivePacket.getOffset(),receivePacket.getLength());
if(receiveContent.equals("滚")) {
        System.out.println("他不想跟你说话!");
        break;
        }
    system.out.println("他说:" + receiveContent);
            }

运行结果:

标签: java eclipse

本文转载自: https://blog.csdn.net/qq_59616295/article/details/125827320
版权归原作者 记得爱蓝色 所有, 如有侵权,请联系我们删除。

“基于TCP与UDP网络编程”的评论:

还没有评论