基于Socket的UDP和TCP编程

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正常只能进行一对一通信,在当前结束通信后才能让下一个主机进行通信,所以为了实现多发多收,用多线程,将每一个主机分一个单独的线程给他同时进行和服务端进行通信。

客户端用什么流进行的传输,服务端也要用什么流来进行接收,也要用同样的读取方法。

当客户端断开连接,服务端没有收到通知会抛出异常,所以在服务端的等待窗口添加异常处理,当客户端断开连接,服务端也可以在异常处理提示客户端已经断开连接。

  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值