飞道的博客

Java网络编程聊天小案例

413人阅读  评论(0)

Java网络编程聊天小案例

网络编程

  1. 每一台计算机通过网络连接起来,达到了数据互动的效果,而网络编程所解决的问题就是如何让程序与程序之间实现数据的通讯与互动
    在吗?你是GG还是MM?

(一) 网络模型概述

(1) 两大模型

网络模型一般是指:

  1. OSI(Open System Interconnection开放系统互连)参考模型
  2. TCP/IP参考模型

(2) 网络模型七层概述

  • 物理层:主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流(就是由1、0转化为电流强弱来进行传输,到达目的地后在转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特。
  • 数据链路层:主要将从物理层接收的数据进行MAC地址(网卡的地址)的封装与解封装。常把这一层的数据叫做帧。在这一层工作的设备是交换机,数据通过交换机来传输。
  • 网络层:主要将从下层接收到的数据进行IP地址(例192.168.0.1)的封装与解封装。在这一层工作的设备是路由器,常把这一层的数据叫做数据包。
  • 传输层:定义了一些传输数据的协议和端口号(WWW端口80等),如:TCP(传输控制协议,传输效率低,可靠性强,用于传输可靠性要求高,数据量大的数据),UDP(用户数据报协议,与TCP特性恰恰相反,用于传输可靠性要求不高,数据量小的数据,如QQ微信聊天数据就是通过这种方式传输的)。主要是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。常常把这一层数据叫做段。
  • 会话层:通过传输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接受会话请求(设备之间需要互相认识可以是IP也可以是MAC或者是主机名)
  • 表示层:主要是进行对接收的数据进行解释、加密与解密、压缩与解压缩等(也就是把计算机能够识别的东西转换成人能够能识别的东西(如图片、声音等)。
  • 应用层:主要是一些终端的应用,比如说FTP(各种文件下载),WEB(IE浏览),QQ之类的(可以把它理解成我们在电脑屏幕上可以看到的东西.就是终端应用)。

(二) 网络编程三要素

(1) IP地址

A:IP地址概述:IP地址是网络中计算机的唯一标识

我们应该或多或少都有见过IP地址的格式 http://xxx.xxx.xxx.xxx大致应该是类似这样的,但是计算机不是只能识别二进制的数据,但是很显然,我们的IP地址确实不是二进制的,这是什么原因呢?

我们先随便拿一个IP地址举个例子看看

IP:192.168.1.100

换算:11000000 10101000 00000001 01100100

但是如果我们日后需要用到这个IP地址的时候,记忆起来就比较麻烦,所以,为了方便表示IP地址,我们就把IP地址的每一个字节上的数据换算成十进制,然后用 ’ . ’ 分开来表示:“点分十进制”

B:IP地址的组成:网络号段+主机号段

A类:第一号段为网络号段+后三段的主机号段,一个网络号:256256256 = 16777216

B类:前二号段为网络号段+后二段的主机号段,一个网络号:256*256 = 65536

C类:前三号段为网络号段+后一段的主机号段,一个网络号:256

C:IP地址的分类

A类

  1.0.0.1---127.255.255.254    

(1)10.X.X.X是私有地址(私有地址就是在互联网上不使用,而被用在局域网络中的地址)

(2)127.X.X.X是保留地址,用做循环测试用的

B类

 128.0.0.1---191.255.255.254    
 172.16.0.0---172.31.255.255是私有地址
 169.254.X.X是保留地址

C类

  192.0.0.1---223.255.255.254    192.168.X.X是私有地址

D类

  224.0.0.1---239.255.255.254

E类

240.0.0.1---247.255.255.254

两个DOS命令

  1. ipconfig 查看本机ip地址

  2. ping 后面跟ip地址, 测试本机与指定的ip地址间的通信是否有问题

特殊IP地址

127.0.0.1 回环地址(表示本机)//也就是说,ping本机的IP地址相当于ping 127.0.0.1

x.x.x.255 广播地址

x.x.x.0 网络地址

(2) 端口

  • 物理端口 网卡口
  • 逻辑端口 我们指的就是逻辑端口

每个网络程序都会至少有一个逻辑端口

用于标识进程的逻辑地址,不同进程的标识

0 ~ 1024 为被系统使用或保留的端口号,0 ~ 65535为有效的端口号,也就是说我们要对一些程序定义端口号的时候,要选择1024 ~ 65535范围内的整数数字。

比如,以前学过的MySQL的端口号是3306,SQLServer的端口号是1433,查了一下Oracle的端口号是1521。

一定要把这些数据库对应的端口号,藏在深深的脑海里,以后在连接数据库的时候,会使用到端口号。

(3) 协议

第一种:TCP协议 英文名:Transmission Control Protocol 中文名:传输控制协议 协议说明:TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。

  • 举例:打电话,需要双方都接通,才能进行对话
  • 特点:效率低,数据传输比较安全

第二种:UDP协议 英文名:User Datagram Protocol 中文名:数据报协议 协议说明:UDP是一种面向无连接的传输层通信协议。

  • 举例:发短信,不需要双方建立连接,But,数据报的大小应限制在64k以内
  • 特点:效率高,数据传输不安全,容易丢包

(三) 控制台简单聊天案例

(1) UDP版本 V1.0

SendDemo

package cn.itcast.network.demo.udp_v1;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/*
 UDP协议发送数据
    A:创建发送端socket对象
    B:创建数据,并把数据打包
    C:调用socket对象的发送方法发送数据包
    D:释放资源
 */
public class SendDemo {
   
    public static void main(String[] args) throws IOException {
   
        //创建socket对象
        DatagramSocket ds=new DatagramSocket();
        //创建数据并把数据打包
        //DatagramPacket(byte[] buf, int length, InetAddress address, int port)
        byte[] bys="Hello,BWH!".getBytes();//把字符串转成字符数组
        int length=bys.length;
        InetAddress address=InetAddress.getByName("localhost");//本地ip地址
        int port=10086;//自拟
        DatagramPacket dp=new DatagramPacket(bys,length, address, port);
        //调用socket对象的方法发送数据包
        ds.send(dp);
        //释放资源
        ds.close();//底层依赖IO流,所以要释放资源
    }
}

ReceiveDemo

package cn.itcast.network.demo.udp_v1;

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

/*
    UDP协议接收数据
        A:创建接收端Socket对象
        B:创建一个数据包(接收容器)
        C:调用Socket对象的,接收方法接收数据
        D:解析数据包,并显示在控制台
        E:释放资源
 */
public class ReceiveDemo {
   
    public static void main(String[] args) throws IOException {
   
        //创建接收端socket对象
        //DatagramSocket(int port)
        DatagramSocket ds=new DatagramSocket(10086);
        //创建一个数据包(接收容器)
        // DatagramPacket(byte[] buf, int length)
        byte[] bys=new byte[1024];
        int length=bys.length;
        DatagramPacket dp=new DatagramPacket(bys,length);
        //调用Socket对象的接收方法接收数据
        // public void receive(DatagramPacket p)
        ds.receive(dp);
        //解析数据包,并显示在控制台
        //获取对方ip
        //public InetAddress getAddress()
        InetAddress address=dp.getAddress();
        String ip=address.getHostAddress();
        //public byte[] getData():获取数据缓冲区
        //public int getLength():获取数据的实际长度
        byte[] bys2=dp.getData();
        int len=dp.getLength();
        String s=new String(bys2,0,len);
        System.out.println(ip+": "+s);
        //释放资源
        ds.close();
    }
}

先启动ReceiveDemo,再启动SendDemo,查看结果

(2) UDP 版本V2.0

UDP 版本V2.0可在控制台输入内容

SendDemo

package cn.itcast.network.demo.udp_v2;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;


public class SendDemo {
   
    public static void main(String[] args) throws IOException {
   
        //创建发送端socket对象
        DatagramSocket ds=new DatagramSocket();
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        String line=null;
        while((line= br.readLine())!=null){
   
            if("886".equals(line)){
   
                break;
            }
            //创建数据并打包
            byte[] bys=line.getBytes();
            DatagramPacket dp=new DatagramPacket(bys,bys.length, InetAddress.getByName("localhost"),10086);
            //发送数据
            ds.send(dp);
        }
        //释放资源
        ds.close();
    }
}

ReceiveDemo

package cn.itcast.network.demo.udp_v2;

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


public class ReceiveDemo {
   
    public static void main(String[] args) throws IOException {
   
        //创建接收端的Socket对象
        DatagramSocket ds=new DatagramSocket(10086);
        while(true){
   
            //创建一个包裹
            byte[] bys=new byte[1024];
            DatagramPacket dp=new DatagramPacket(bys,bys.length);
            //接收数据
            ds.receive(dp);
            //解析数据
            String ip=dp.getAddress().getHostAddress();
            String s=new String(dp.getData(),0,dp.getLength());
            System.out.println(ip+":"+s);
        }
        //释放资源,但是接收端服务器应该一直开启
        //ds.close();
    }
}

发送端依次输入消息发送,当输入886停止发送消息


接收端接收消息

(3) UDP 版本V3.0

UDP 版本V3.0可不用分别开启发送方和接收方,直接运行聊天室 ChatRoom 即可

ChatRoom

package cn.itcast.network.demo.udp_v3;

import java.net.DatagramSocket;
import java.net.SocketException;

public class ChatRoom {
   
    public static void main(String[] args) throws SocketException {
   
        DatagramSocket dsSend=new DatagramSocket();
        DatagramSocket dsReceive=new DatagramSocket(10086);
        SendThread st=new SendThread(dsSend);
        ReceiveThread rt=new ReceiveThread(dsReceive);
        Thread t1=new Thread(st);
        Thread t2=new Thread(rt);
        t1.start();
        t2.start();
    }
}

SendThread

package cn.itcast.network.demo.udp_v3;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class SendThread implements Runnable {
   
    private DatagramSocket ds;

    public SendThread(DatagramSocket ds) {
   
        this.ds = ds;
    }
    @Override
    public void run() {
   
        try {
   
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String line = null;
            while ((line = br.readLine()) != null) {
   
                if ("886".equals(line)) {
   
                    break;
                }
                // 创建数据并打包
                byte[] bys = line.getBytes();
                DatagramPacket dp = new DatagramPacket(bys, bys.length, InetAddress.getByName("localhost"), 10086);
                // 发送数据
                ds.send(dp);
            }
            // 释放资源
            ds.close();
        } catch (IOException e) {
   
            e.printStackTrace();
        }
    }
}

ReceiveThread

package cn.itcast.network.demo.udp_v3;

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

public class ReceiveThread implements Runnable{
   
    private DatagramSocket ds;

    public ReceiveThread(DatagramSocket ds) {
   
        this.ds = ds;
    }

    @Override
    public void run() {
   
        try {
   
            while (true) {
   
                //创建一个包裹
                byte[] bys = new byte[1024];
                DatagramPacket dp = new DatagramPacket(bys, bys.length);
                //接收数据
                ds.receive(dp);
                //解析数据
                String ip = dp.getAddress().getHostAddress();
                String s = new String(dp.getData(), 0, dp.getLength());
                System.out.println("from " + ip + " data is : " + s);
            }
        } catch (IOException e) {
   
            e.printStackTrace();
        }
    }
}

测试结果

(4) TCP版本

TCP是基于字节流的传输层通信协议,所以TCP编程是基于IO流编程。

对于客户端,我们需要使用Socket类来创建对象。对于服务器端,我们需要使用ServerSocket来创建对象,通过对象调用accept()方法来进行监听是否有客户端访问。

客户端与服务器端图解:

代码实现:

Client 客户端

package cn.itcast.network.demo.tcp;

import java.io.*;
import java.net.Socket;

public class Client {
   
    public static void main(String[] args) throws IOException {
   
        Socket s=new Socket("localhost",22222);
        //键盘录入对象
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        //把通道内的流包装一下
        BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        String line=null;
        while((line=br.readLine())!=null){
   
            if("886".equals(line)){
   
                break;
            }
            bw.write(line);
            bw.newLine();
            bw.flush();
        }
        s.close();

    }
}

Server 服务端

package cn.itcast.network.demo.tcp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
   
    public static void main(String[] args) throws IOException {
   
        ServerSocket ss=new ServerSocket(22222);
        Socket s=ss.accept();
        BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
        String line=null;
        while((line=br.readLine())!=null){
   
            System.out.println(line);
        }
        s.close();
    }
}

测试结果

The End!


转载:https://blog.csdn.net/qq_22075913/article/details/116656994
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场