Java网络编程

最近在B站学习狂神说的网络编程,跟着敲了一遍,总结一下。
客户端在给服务器发送消息或者文件时,要知道两个东西,第一个是要知道对方的host,第二个是对方要知道开放的端口号port

TCP实现聊天

客户端

		//提升权限
 		OutputStream os=null;
 		Socket socket=null;
        try {
            //1.创建一个socket连接
            socket=new Socket("127.0.0.1",9999);//保证与服务器端端口号一致
            //3.发送消息IO流,输出流
            os=socket.getOutputStream();
            os.write("学习tcp聊天中".getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
        	//关闭流写法
            if (os!=null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (socket!=null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

服务器端

		ServerSocket serverSocket=null;
        Socket socket=null;
        InputStream is=null;
        ByteArrayOutputStream baos=null;
        try{
            //1.创建地址
            serverSocket = new ServerSocket(9999);
            //2.等待客户端连接过来
            //阻塞式等待,像scanner输入,如果用户不输入会一直等待
            socket=serverSocket.accept();
            //3.读取客户端的消息
            is= socket.getInputStream();

            //管道流
            baos=new ByteArrayOutputStream();
            byte[] buffer=new byte[1024];
            int len;
            while ((len=is.read(buffer))!=-1){
                baos.write(buffer,0,len);
            }
            System.out.println(baos.toString());
        }catch(IOException e){
            e.printStackTrace();
        }finally {
            if (baos!=null){
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (is!=null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(socket!=null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (serverSocket!=null){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

总结:
1.在客户端连接服务端时需要地址和端口号,地址在本机测试时使用127.0.0.1或localhost,端口号需要在服务器端设置
2.使用流时需要关闭,采取后使用先关闭原则,在finally中进行判断后关闭(重要)
管道流:流是一个类似于管道流动的,而管道流是在输出流上添加一个过滤层,经过对接,使流获取的不是乱码等数据,装饰者模式
管道流工作过程

TCP实现文件上传

客户端

public static void main(String[] args) throws Exception {
      //1.创建一个Socket连接
       Socket socket=new Socket(InetAddress.getByName("127.0.0.1"),9000);
       //2.创建一个输出流
       OutputStream os=socket.getOutputStream();
       //3.读取文件
       FileInputStream fis=new FileInputStream(new File("1.png"));
       //4.写出文件
       byte[] buffer=new byte[1024];
       int len;
       while ((len=fis.read(buffer))!=-1){
           os.write(buffer,0,len);
       }
       //通知服务器,我已经结束了
       socket.shutdownOutput();//我已经传输完了

       //确定服务器接收完毕,才能断开连接
       InputStream is=socket.getInputStream();
       ByteArrayOutputStream baos = new ByteArrayOutputStream();
       byte[] buffer2=new byte[1024];
       int len2;
       while ((len2=is.read(buffer2))!=-1){
           baos.write(buffer2,0,len2);
       }
       System.out.println(baos.toString());
       
       //5.关闭资源
       fis.close();
       os.close();
       socket.close();
    }

服务器端

   public static void main(String[] args) throws Exception {
        //1.创建服务
        ServerSocket serverSocket=new ServerSocket(9000);
        //2.监听客户端连接
        Socket socket = serverSocket.accept();//阻塞式监听,会一直等待连接
        //3.获取输入流
        InputStream is=socket.getInputStream();
        //4.文件输出
        FileOutputStream fos = new FileOutputStream(new File("receive.png"));
        byte[] buffer=new byte[1024];
        int len;
        while ((len=is.read(buffer))!=-1){
            fos.write(buffer,0,len);
        }
        //通知客户端我接收完毕了
        OutputStream os=socket.getOutputStream();
        os.write("我接受完毕了,你可以断开了".getBytes());

        //5.关闭资源
        fos.close();
        is.close();
        socket.close();
        serverSocket.close();
    }

这里采用的是throws方法抛出异常,可以省略try catch代码段

操作顺序:

1.客户端操作顺序

先创建客户端Socket连接

 Socket socket=new Socket(InetAddress.getByName("127.0.0.1"),9000);

创建输出流

OutputStream os=socket.getOutputStream();

创建一个文件流来读取客户端上传的文件

FileInputStream fis=new FileInputStream(new File("1.png"));

创建缓冲区,写出文件

byte[] buffer=new byte[1024];
int len;
  while ((len=fis.read(buffer))!=-1){
      os.write(buffer,0,len);
  }

通知服务器上传完毕

	socket.shutdownOutput();

创建输入流,接收服务器传回来的提示信息,确定服务器端接收完毕后断开
因为服务器传回来是字符串,需要管道流的转换

InputStream is=socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer2=new byte[1024];
 int len2;
 while ((len2=is.read(buffer2))!=-1){
     baos.write(buffer2,0,len2);
 }
 System.out.println(baos.toString());

最后关闭流,可以用判断

fis.close();
os.close();
socket.close();

2.服务器端操作顺序

创建服务器端ServerSocket,同时监听客户端的连接

ServerSocket serverSocket=new ServerSocket(9000);
Socket socket = serverSocket.accept();//阻塞式监听,会一直等待连接

创建一个输入流,用socket接收

InputStream is=socket.getInputStream();

创建文件流,将客户端上传的文件传到服务器

 FileOutputStream fos = new FileOutputStream(new File("receive.png"));
        byte[] buffer=new byte[1024];
        int len;
        while ((len=is.read(buffer))!=-1){
            fos.write(buffer,0,len);
        }

通知客户端接收完毕,可以断开

OutputStream os=socket.getOutputStream();
os.write("我接受完毕了,你可以断开了".getBytes());

关闭资源

fis.close();
os.close();
socket.close();

实现图

UDP发送消息

发送端

		//1.建立Socket
        DatagramSocket socket = new DatagramSocket();
        //2.建包
        String msg="你好服务器";
        InetAddress localhost = InetAddress.getByName("localhost");
        int port=9090;
        //数据,数据起始,数据长度
        DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, localhost, port);
        //3.发送包
        socket.send(packet);
        //4.关闭流
        socket.close();

接收端

  		//开放端口
        DatagramSocket socket = new DatagramSocket(9090);
        //接收数据包
        byte[] buffer=new byte[1024];
        DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
        socket.receive(packet);//阻塞接收

        System.out.println(packet.getAddress().getHostAddress());
        System.out.println(new String(packet.getData(), 0, packet.getLength()));
        //关闭连接
        socket.close();

操作顺序:

1.发送端操作顺序

1.创建DatagramSocket对象

DatagramSocket socket = new DatagramSocket();

2.准备发送的内容

String msg="你好服务器";

3.创建DatagramPacket对象,用来对发送的数据进行打包,需要指定发送内容、数据起始地、发送多少、发送到哪里和接收方的端口号四个参数。

InetAddress localhost = InetAddress.getByName("localhost");
int port=9090;
DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, localhost, port);

4.调用DatagramSocket对象的send()方法发送数据。

socket.send(packet);

5.关闭流

socket.close();

2.接收端操作顺序

1.创建DatagramSocket对象,指定接收方的端口号。

DatagramSocket socket = new DatagramSocket(9090);

2.创建一个byte类型数组,用来接收发送方发送过来的数据。

byte[] buffer=new byte[1024];

3.创建DatagramPacket对象,接收数据并打包。

DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);

4.调用DatagramSocket对象的receive()方法用于接收数据。

socket.receive(packet);//阻塞接收

5.使用String类的构造方法将byte类型的数组中的数据转化成String类型并显示。

System.out.println(packet.getAddress().getHostAddress());//查看地址
System.out.println(new String(packet.getData(), 0, packet.getLength()));

6.关闭流

socket.close();

UDP实现聊天

发送端

DatagramSocket socket=new DatagramSocket(8888);//自己的端口号
        //准备数据,控制台读取System.in
        BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
        String data=reader.readLine();
        byte[] dataBytes = data.getBytes();
        DatagramPacket packet=new DatagramPacket(dataBytes,0,dataBytes.length,new InetSocketAddress("localhost",6666));
        socket.send(packet);
        socket.close();

接收端

 DatagramSocket socket = new DatagramSocket(6666);
        while (true) {
            //准备接收包裹
            byte[] container = new byte[1024];
            DatagramPacket packet = new DatagramPacket(container, 0, container.length);
            socket.receive(packet);//阻塞式接受包裹

            //断开连接
            byte[] data = packet.getData();
            String receiveData = new String(data, 0, packet.getLength());
            System.out.println(receiveData);
            if ("bye".equals(receiveData)) {
                break;
            }
        }
        socket.close();

操作顺序

1.发送端操作顺序

1.创建DatagramSocket对象

DatagramSocket socket=new DatagramSocket();

2.实现聊天就要使用控制台获取数据,采用BufferedReader字符缓冲流

BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));

3.将存入流中的数据读出来存进String中,在转化成具体数据
*注意,从流中读出来的数据不可读,要转化成字节

String data=reader.readLine();
byte[] dataBytes = data.getBytes();

4.打包数据

DatagramPacket packet=new DatagramPacket(dataBytes,0,dataBytes.length,new InetSocketAddress("localhost",6666));

5.调用DatagramSocket对象的send()方法发送数据。

socket.send(packet);

6.关闭流

socket.close();

2.接收端操作顺序

1.创建DatagramSocket对象,指定端口号

DatagramSocket socket = new DatagramSocket(6666);

2.字节数组接收数据

byte[] container = new byte[1024];

3.打包接收的数据

DatagramPacket packet = new DatagramPacket(container, 0, container.length);

4.调用DatagramSocket对象的receive()方法用于接收包裹

socket.receive(packet);//阻塞式接受包裹

5.读数据,做断开连接的判断,packet.getData()读数据存放在字节数组中,在使用String类的构造方法将byte类型的数组中的数据转化成String类型并显示。

byte[] data = packet.getData();
String receiveData = new String(data, 0, packet.getLength());
System.out.println(receiveData);

6.判断

if ("bye".equals(receiveData)) {
	break;
}

7.关闭流

socket.close();

UDP多线程聊天

线程发送端

public class TheadSend implements Runnable  {
    DatagramSocket socket = null;
    BufferedReader reader=null;

    private String toIP;
    private int toPort;

    public TheadSend(String toIP, int toPort) {
        this.toIP = toIP;
        this.toPort = toPort;

        try {
            socket = new DatagramSocket();
            reader=new BufferedReader(new InputStreamReader(System.in));
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public TheadSend() { }
    @Override
    public void run() {
        while (true) {
            try {
                String data = reader.readLine();
                byte[] dataBytes = data.getBytes();
                DatagramPacket packet = new DatagramPacket(dataBytes, 0, dataBytes.length, new InetSocketAddress(this.toIP, this.toPort));
                socket.send(packet);
                if ("bye".equals(data)) {
                    break;
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        socket.close();
    }
}

线程接收端

public class TheadReceive implements Runnable{
    DatagramSocket socket=null;
    byte[] container=null;

    private int port;
    private String msgFrom;
    public TheadReceive(int port,String msgFrom) {
        this.port = port;
        this.msgFrom=msgFrom;
        try {
            socket = new DatagramSocket(port);
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void run() {
        while (true) {
            try {
                //准备接收包裹
                container = new byte[1024];
                DatagramPacket packet = new DatagramPacket(container, 0, container.length);
                socket.receive(packet);//阻塞式接受包裹

                //断开连接
                byte[] data = packet.getData();
                String receiveData = new String(data, 0, packet.getLength());
                System.out.println(msgFrom+":"+receiveData);
                if ("bye".equals(receiveData)) {
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        socket.close();
    }
}

以学生老师聊天为例
学生启动线程

 public static void main(String[] args) {
       //开启两个线程
     new Thread(new TheadSend("localhost",9999)).start();//发送的IP地址,接收端口号
     new Thread(new TheadReceive(8888,"老师")).start();//自己端口号,以及接收谁传回来的消息
}

老师启动线程

public static void main(String[] args) {
        //开启两个线程
        new Thread(new TheadSend("localhost",8888)).start();
        new Thread(new TheadReceive(9999,"学生")).start();
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值