Java学习记录(二十一)网络编程

CS架构和BS架构

这两个架构是现在市面上主流的两个架构,CS架构主要是客户端+服务器,而BS架构主要是网页+服务器。BS架构的优点是方便,所有数据通过服务器传输,缺点也很明显,由于所有数据都是通过网络传输,导致BS架构里面的数据不能过多,否则则会导致用户由于网络问题出现卡顿的情况。而CS架构的优点就是将大量的基础信息例如音乐,图片放入客户端让用户下载到本地中,网络只传送一些数据,就会使用户在使用时不用考虑数据大小的问题,缺点就是需要将客户端下载到本地,不方便。

网络编程的三要素(IP,端口号,协议)

双方各自的IP地址:设备在网络中的地址

使用传输软件的端口号:一个软件对应一个端口号,只有端口号相同才能进行数据传输(也就是双方都只使用一个软件才能进行数据交流,例如都使用微信才能相互交流)

网络传输规则:数据在网络中传递的规则如:TCP,https等

IP以及主机名的获取

通过InetAddress类里面的静态方法getbyName方法能通过传入的主机名或者IP查找到对应的IP地址。

通过InetAddress实例化对象调用getHostName方法能通过传入的IP得到对应的主机名,但是如果传入的IP不在局域网内,则会返回IP而不是主机名。

通过调用InetAddress实例化对象调用getHostAddress方法能得到对应主机的IP地址

上述具体实现如下:

package com.itazhang.Demo1;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;

public class MyIntaddressDemo1 {
    public static void main(String[] args) throws UnknownHostException {
        //可以通过主机名和ip地址查找到Ip
        InetAddress address = InetAddress.getByName("192.168.0.100");
        System.out.println(address);
        //使用IP地址得打主机名,如果局域网内没有这台电脑就会返回IP地址
        String name = address.getHostName();
        System.out.println(name);
        //查看ip
        String hostAddress = address.getHostAddress();
        System.out.println(hostAddress);
    }
}

端口号

网络通信协议 

UDP协议:UDP协议是面向无连接的传输协议,他在传输数据时不会检查目的地与发送地网络是否联通,会直接将数据发送过去,且一次传输有大小限制,优点为传输快,缺点为数据在传输过程中易丢失,数据不安全

TCP协议:TCP协议是面向连接的通信协议,在传输之前会坚持发送地和目的地的网络是否连接,如果连接,才会将数据发送,且一次传输没有大小限制,优点为数据传输安全,不丢失,缺点为传 输数据的速度慢。

UDP通信协议

UDP的传输数据主要包括以下几个步骤

1、创建用来传输数据的对象

//创建发送数据的对象
DatagramSocket ds = new DatagramSocket();

2、将需要传输的数据打包成字节数组

String str = "我是测试消息";
//将需要发送的数据转化为字节数组
byte[] bytes = str.getBytes();

3、找到自己需要发送的地址

//创建需要发送的地址
InetAddress address = InetAddress.getByName("127.0.0.1");

4、写出发送到对方的端口

//创建发送数据的端口号
int port = 10086;

5、将上述信息传入数据打包的对象,将数据打包

传递参数格式(需要传输的数据转化成的字节数组,需要传输的长度,目的IP,传输的端口号)

//对数据进行打包加工
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);

6、传输数据,释放资源

ds.send(dp);
ds.close();

UDP的接收数据主要包括以下几个步骤

1、创建接收数据的对象,也是DatagramSocket,其中传入接收的端口

//创建接收对象
DatagramSocket ds = new DatagramSocket(10086);

2、创建对象用来接收数据,也是用字节数组的方式接收

byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
ds.receive(dp);

3、解析数据,可以用dp调用各种属性的get方法解析数据,将传递过来的字节数组转化为相应的类型

//解析数据包
InetAddress address = dp.getAddress();
int port = dp.getPort();

4、打印数据,释放资源,是将上述转化类型的代码放到打印方法中的

//打印输出,释放资源
System.out.println("是从地址为"+address+"端口号为"+port+"的电脑发出的数据:"+new String(bytes,0,bytes.length));
ds.close();

一个利用上述传输接收方法实现的简易聊天室

实现一个简易聊天室,输入端输入886结束输入,接收端无限循环接收,最后手动关闭

接收端实现如下:

package com.itazhang.Demo2;

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

public class GetMessageDemo2 {
    public static void main(String[] args) throws IOException {
        //创建接收对象
        DatagramSocket ds =new DatagramSocket(10086);
        //创建数据包接收数据
        byte[] bytes = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
        while (true){
            ds.receive(dp);
            InetAddress address = dp.getAddress();
            int port = dp.getPort();
            String s = new String(bytes, 0, bytes.length);
            //将数据解析并打印
            System.out.println("这是从地址为"+address+"端口号为"+port+"的数据"+s);
        }
    }
}

发送端实现如下:

package com.itazhang.Demo2;

import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

public class SendMessageDemo2 {
    public static void main(String[] args) throws IOException {
        //创建发送对象
        DatagramSocket ds = new DatagramSocket();

        Scanner sc = new Scanner(System.in);

        while(true){
            System.out.println("请输入你想要发送的数据:");
            String s = sc.nextLine();
            if(s.equals("886")){
                break;
            }else {
                //打包数据
                byte[] bytes = s.getBytes();
                InetAddress address = InetAddress.getByName("127.0.0.1");
                int port = 10086;
                //发送数据
                DatagramPacket dp = new DatagramPacket(bytes, bytes.length,address,port);
                ds.send(dp);
            }
        }

        //释放资源
        ds.close();
    }
}

三种发送方式,单播,组播,广播

TCP通信协议 

tcp通信协议在传输时是通过客户端发送,服务端接收这个特点进行通信的。

客户端发送数据步骤为:创建Socket发送对象,在创建时传入要发送到的IP和端口号,利用Socket对象获取输出流,再通过输出流将数据发出,实现代码如下:

package com.itazhang.Demo3;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

public class Client {
    public static void main(String[] args) throws IOException {
        //创建socket对象,并传入需要连接的Ip地址和端口
        Socket socket = new Socket("127.0.0.1",10086);
        //通过对象获取到输出流
        OutputStream os = socket.getOutputStream();
        //通过输出流的write方法将数据传输
        os.write("abcabc".getBytes());
        //释放资源
        os.close();
        socket.close();
    }
}

服务端接收数据步骤如下:创建ServerSocket接收对象,创建该对象的时候传入接收的端口号,然后通过该接收对象调用输入流,再通过输入流的read方法读取到数据,并将数据转化为对应的类型,最后释放资源,实现TCP通信,实现代码如下:

(因为默认中文为三个字节,但下列代码是将字节一个一个的读取并转换,所以如果用下列方法读取中文数据的话会显示乱码,如果要实现对中文的传输以及阅读,需要将下列代码中的字节输入流用转换流转换,即字符输入流,这样就不会出现一个字符一个字符的读取,也就可以传输中文)

package com.itazhang.Demo3;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(10086);
        Socket socket = ss.accept();
        InputStream is = socket.getInputStream();
        int temp;
        while (true){
            temp = is.read();
            if(temp == -1){
                break;
            }else{
                System.out.println((char)temp);
            }
        }
        is.close();
        ss.close();
    }
}
TCP通信协议练习

实现一个可以多次发送数据的聊天室,能发中文,且能被接收

客户端(发送),在发送数据时,因为需要接受中文的缘故,所以采用了缓冲输出流的方法,这种方法只会在缓冲区放慢或者关闭缓冲区才会发送数据,所以需要在每次发送数据时调用flush方法刷新缓冲区,让每一次输入数据都直接发送过去

package com.itazhang.TCPDemo4;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

public class Exercise1Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1",10086);
        OutputStream os = socket.getOutputStream();
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
        Scanner sc = new Scanner(System.in);
        while(true){
            System.out.println("请输入你想传输的话");
            String s = sc.nextLine();
            if("886".equals(s)){
                break;
            }else{
                bw.write(s);
                bw.newLine();
                bw.flush();
            }
        }
    }
}

服务端(接收)

package com.itazhang.TCPDemo4;

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

public class Exercise1Server {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(10086);
        Socket socket = ss.accept();
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String s;
        while(true){
            s = br.readLine();
            if(s == null){
                break;
            }else{
                System.out.println(s);
            }
        }
        socket.close();
        ss.close();
    }
}

练习(一)

使用TCP进行文本文件传输,文件里可能有中文

分析:先将文件的数据读取出,再将其传输,在客户端先接收数据,再将数据写入文件,因为有可能文件中有中文,所以得用转换流将字节流转换(记得关流)

客户端实现如下:

package com.itazhang.TCPExercise3;

import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.ArrayList;

public class Client {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("D:\\11Codingtext\\MySocketnet\\a.txt");
        ArrayList<Integer> list = new ArrayList<>();
        int temp;
        while (true){
            temp = fr.read();
            if(temp==-1){
                break;
            }else{
                list.add(temp);
            }
        }

        Socket socket = new Socket("127.0.0.1",10086);
        OutputStream os = socket.getOutputStream();
        OutputStreamWriter osw = new OutputStreamWriter(os);
        for (Integer integer : list) {
            osw.write(integer);
        }

        osw.close();
        socket.close();
        fr.close();


    }
}

服务端实现如下:

package com.itazhang.TCPExercise3;

import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(10086);
        Socket socket = ss.accept();
        InputStream is = socket.getInputStream();
        InputStreamReader isr = new InputStreamReader(is);

        FileWriter fw = new FileWriter("D:\\11Codingtext\\MySocketnet\\b.txt");

        int temp;
        while(true){
            temp = isr.read();
            if(temp == -1){
                break;
            }else{
                fw.write(temp);
            }
        }
        fw.close();
        ss.close();

    }
}

练习(二)

使用TCP协议进行图片文件传输(图片只能使用字节流)

客户端

package com.itazhang.Demo5;

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

public class Client {
    public static void main(String[] args) throws IOException {
        //创建套接字,输出文件流
        Socket socket = new Socket("127.0.0.1",10086);
        OutputStream os = socket.getOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(os);

        //读取本地文件数据
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\11Codingtext\\MySocketnet\\maomao.jpg"));
        int temp;
        byte[] bytes = new byte[1024];
        while(true){
            temp = bis.read(bytes);
            if(temp == -1){
                break;
            }else {
                bos.write(bytes,0,temp);
            }
        }
        bos.flush();
        socket.close();
        bis.close();
    }

}

服务端

package com.itazhang.Demo5;

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

public class Server {
    public static void main(String[] args) throws IOException {
        //创建套接字,创建接收输入流
        ServerSocket ss = new ServerSocket(10086);
        Socket socket = ss.accept();
        InputStream is = socket.getInputStream();
        BufferedInputStream bis = new BufferedInputStream(is);

        //创建输出流,将读取的文件写入新文件
        byte[] bytes = new byte[1024];
        int temp;
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\11Codingtext\\MySocketnet\\temp.jpg"));
        while(true){
            temp = bis.read(bytes);
            if(temp == -1){
                break;
            }else{
                bos.write(bytes,0,temp);
            }
        }
        bos.flush();
        ss.close();
        bos.close();
    }
}

练习(二)(重点掌握)

要求多线程实现图片的传输,每个线程创建并开启之后会出现对应的一个新的jpg文件,例如第一个线程开启为1.jpg,第二个开启就是生成2.jpg。

线程类代码如下:通过构造方法,将每一次 开启线程后,所需要传输的socket套接字传输给Myrunnable这个类

package com.itazhang.Demo5;

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

public class MyRunnable implements Runnable{
    Socket socket;
    static int count = 1;

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

    @Override
    public void run() {
        InputStream is = null;
        try {
            is = socket.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        BufferedInputStream bis = new BufferedInputStream(is);

        //创建输出流,将读取的文件写入新文件
        byte[] bytes = new byte[1024];
        int temp;
        BufferedOutputStream bos = null;
        synchronized (MyRunnable.class){
            try {
                bos = new BufferedOutputStream(new FileOutputStream("D:\\11Codingtext\\MySocketnet\\" +count+ ".jpg"));
                count++;
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
        while(true){
            try {
                if (!((temp = bis.read(bytes))!=-1)) break;
                bos.write(bytes,0,temp);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {
            bos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            bos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

服务端代码实现如下:下面每开启一个线程对应一个用户

package com.itazhang.Demo5;

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

public class Server {
    public static void main(String[] args) throws IOException {
        //创建套接字,创建接收输入流
        ServerSocket ss = new ServerSocket(10086);
        while (true){
            Socket socket = ss.accept();
            //开启线程,一个用户对应一条线程
            new Thread(new MyRunnable(socket)).start();
            new Thread(new MyRunnable(socket)).start();
            new Thread(new MyRunnable(socket)).start();
            new Thread(new MyRunnable(socket)).start();
        }
    }
}

客户端代码如下:

package com.itazhang.Demo5;

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

public class Client {
    public static void main(String[] args) throws IOException {
        //创建套接字,输出文件流
        Socket socket = new Socket("127.0.0.1",10086);
        OutputStream os = socket.getOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(os);

        //读取本地文件数据
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\11Codingtext\\MySocketnet\\maomao.jpg"));
        int temp;
        byte[] bytes = new byte[1024];
        while(true){
            temp = bis.read(bytes);
            if(temp == -1){
                break;
            }else {
                bos.write(bytes,0,temp);
            }
        }
        bos.flush();
        socket.close();
        bis.close();
    }

}

  • 20
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值