Java 使用UDP与TCP协议,客户端与服务器进行简单交互

计算机网络
将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统
网络模型
OSI(Open System Interconnection 开放系统互连)七层参考模型
物理层:主要定义物理设备标准。
数据链路层:主要将从物理层接收的数据进行MAC地址的封装与解封装。通常将该层的数据叫做帧,数据通过交换机来传输。
网络层:主要将从下层接收到的数据进行IP地址的封装与解封装。该层的数据叫做数据包,工作的设备是路由器。
传输层:定义了一些传输协议和端口号。
会话层:通过传输层建立数据传输的通路。
表示层:主要是进行对接收的数据进行解释、加密与解密、压缩与解压缩等(把计算机能够识别的东西转换成人能够识别的东西)
应用层:主要是一些终端的应用。
IP地址
InetAddress:网络中的设备表示,类似于计算机的身份证号
IP地址的组成
IP地址=网路地址+主机地址
IP地址分类
A类IP地址:第一段号码为网络地址,剩下三段为本地计算机号码
B类IP地址:前两段号码为网络地址,剩下两段为本地计算机号码
B类IP地址:前三段号码为网络地址,剩下一段为本地计算机号码
特殊地址
127.0.0.1 回环地址,用于测试本机的网络是否有问题
DOS命令 ipconfig:可查看本机的IP地址
xxx.xxx.xxx.255 广播地址
端口
用于标识进程的逻辑地址,不同进程的端口号不同
物理端口:网卡口
逻辑端口:每个程序都有一个逻辑端口,有效端口0~ 65535,其中0~1023是系统使用或保留的端口
协议
UDP
将数据源与数据封装在数据包中,不需要建立连接,属于不可靠协议,速度快。
每个数据包限制大小为64k
TCP
建议连接,形成传输数据的通道,属于可靠协议,效率低。
在连接中进行大量数据传输
InetAddress类
用于获取IP地址并进行操作,Java提供InetAddress类
InetAddress类的常见功能
​ public static InetAddress getByName(String host) 通过主机名获取主机的IP地址
​ public String getHostAddress() 获取IP
​ public String getHostName() 获取主机名
​ getLocalHost();
Socket类
Socket原理:
通信两端都有Socket,网络间的通信其实就是Socket间的通信,数据在Socket间通过IO流进行传输
UDP协议发送数据
创建客户端

public class SocketTest {
    public static void main(String[] args) throws IOException {
        //创建客户端UDP的Socket
        DatagramSocket ds=new DatagramSocket();
        //封装数据
        //DatagramPacket( byte[] buf, int length, InetAddress address,int port)
        //构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
        //创建数据包
        byte[] bytes="PlkoNya".getBytes();
        //获取本机的ip(两种形式获取)
        String s=InetAddress.getByName("PlkoNya").getHostAddress();
        byte[] add = InetAddress.getByName("PlkoNya").getAddress();
        System.out.println(s);
        //获取本机的IP地址并以字符串的形式输出
        System.out.println(InetAddress.getLocalHost().getHostAddress());
        //服务器的ip 因为服务器就是本机,所以将本机的IP传入数据报包中
        InetAddress address=InetAddress.getByAddress(add);
        //port是服务端的端口号 数据包中的参数1,数据存放的byte数组,参数2,数据存放的数组的长度,参数3,发送的主机ip,参数4,该主机上的端口号
        DatagramPacket dp=new DatagramPacket(bytes,bytes.length,address,9999);
        //发送数据包
        ds.send(dp);
        //释放资源
        ds.close();
    }
}

创建服务器
运行的时候需要先开启服务器,然后再打开客户端发送文件。

public class UDPServer {
    public static void main(String[] args) throws IOException {
        //创建服务端 DatagramSocket( int port) 创建服务端的Socket并暴露端口号
        DatagramSocket ds=new DatagramSocket(9999);
        //创建空的数据包,用于接收数据包 DatagramPacket( byte[] buf, int length)
        byte[] bytes=new byte[1024];
        DatagramPacket dp=new DatagramPacket(bytes,bytes.length);
        //接收数据
        System.out.println("服务器开启,等到接收数据");
        ds.receive(dp);//阻塞的方法,如果服务器开启后,没有数据传输过来,就会一直阻塞
        //获取数据包的数据
        byte[] data=dp.getData();
        //获取数据包中的数据的实际长度
        int lenth=dp.getLength();
        //获取发送方的IP
        String ip=dp.getAddress().getHostAddress();
        //将字节数组转换成字符串
        String s=new String(data,0,lenth);
        System.out.println(ip+"给你发来消息:"+s);
        //释放资源
        ds.close();
    }
}

TCP协议传输数据
需要创建客户端与服务器建立双方的连接通道
客户端

public static void main(String[] args) throws IOException {
        //创建客户端的Socket
        //创建一个流套接字并将其连接到指定IP地址的指定端口号
        Socket socket = new Socket("192.168.43.74", 9999);
        //获取通道中的输出流
        OutputStream out=socket.getOutputStream();
        //发送数据
        out.write("Nya".getBytes());
        //释放资源
        socket.close();
    }
}

服务器

public class TCPServer {
    public static void main(String[] args) throws IOException {
        //创建服务端的Socket并暴露端口号
        ServerSocket ss = new ServerSocket(9999);
        System.out.println("服务器开启,等待连接。。。");
        //侦听客户端的连接 阻塞式方法,在方法在连接传入前一直阻塞
        Socket accept = ss.accept();
        //获取通道中的输入流
        InputStream in = accept.getInputStream();
        byte[] bytes = new byte[1024];
        int len = in.read(bytes);
        //转换成字符串
        String s=new String(bytes,0,len);
        System.out.println(s);
        //关闭服务器
        ss.close();
    }
}

TCP键盘录入数据并在服务器上将数据记录在文件中
客户端

public class Client {
    public static void main(String[] args) throws IOException {
        Socket client = new Socket("192.168.43.74",8888);
        OutputStream clientOut = client.getOutputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(clientOut));
        String msg = null;
        while (true){
            System.out.println("请输入消息:");
            if ((msg=br.readLine())!=null){
                bw.write(msg);
                bw.newLine();
                bw.flush();
                if(msg.matches("8+")){
                   client.shutdownOutput();
                   client.close();
                    break;
                }
            }
        }
    }
}

服务器
服务器可以在文件中记录消息日志文件。哪个IP在何时发的什么消息。

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket server = new ServerSocket(8888);
        BufferedWriter bw = new BufferedWriter(new FileWriter("msg.txt",true));
        bw.newLine();
        System.out.println("服务器已开启,等待连接...");
        Socket link = server.accept();
        System.out.println("客户端IP地址:"+link.getInetAddress().getHostAddress()+"已连接");
        BufferedReader br = new BufferedReader(new InputStreamReader(link.getInputStream()));
        String msg=null;
        Date date = new Date();
        SimpleDateFormat sdp = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        while ((msg=br.readLine())!=null){
            date.setTime(System.currentTimeMillis());
            String log=link.getInetAddress().getHostAddress()+" "+sdp.format(date)+"发送消息文件:";
            bw.write(log);
            bw.flush();
            bw.write(msg);
            bw.flush();
            bw.newLine();
        }
    }
}

TCP多线程上传文件
服务器(将上传文件功能交给其他类)

public class Server {
    public static void main(String[] args) throws IOException {
        //创建服务端
        ServerSocket ss = new ServerSocket(6666);
        System.out.println("服务器开启,等待连接....");
        //一个服务端,连接多个客户端
        //侦听通道
        int i=1;
        while (true){
            Socket accept = ss.accept();
            System.out.println((i++)+"个客户已经连接");
            new UpLoadThread(accept).start();
        }
    }
}

该类实现上传文件功能

public class UpLoadThread extends Thread {

    private  Socket socket;

    public UpLoadThread(Socket socket) {
        this.socket=socket;
    }

    @Override
    public void run() {
        try {
            //获取通道中的输入输出流
            InputStream in = socket.getInputStream();
            OutputStream out = socket.getOutputStream();
            //多个客户端上传文件。防止文件覆盖现象,取随机文件名
            FileOutputStream fileout = new FileOutputStream(System.currentTimeMillis() + "temp");
            int temp;
            byte[] bytes=new byte[1024];
            while (((temp=in.read(bytes))!=-1)){
                fileout.write(bytes,0,temp);
            }
            //客户端上传完毕,服务端需要给客户端反馈
            out.write("上传成功!".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户端(其余客户端实现功能一样,只是上传文件的不同而已)

public class Client01 {
    public static void main(String[] args) throws IOException {
        //创建客户端
        Socket Client=new Socket("192.168.43.74",6666);
        //获取通道中的输入流输出流
        InputStream in = Client.getInputStream();
        OutputStream out = Client.getOutputStream();
        //客户端读取文件的流
        FileInputStream filein = new FileInputStream("D:\\Test\\IO类继承关系图.jpg");
        byte[] bytes=new byte[1024];
        int temp;
        while ((temp=filein.read(bytes))!=-1){
            out.write(bytes,0,temp);
            out.flush();
        }
        //客户端传递完毕
        Client.shutdownOutput();
        //读取服务端的反馈
        byte[] rebytes=new byte[1024];
        int len = in.read(rebytes);
        String msg=new String(rebytes,0,len);
        System.out.println(msg);
        //释放资源
        Client.close();
        filein.close();
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值