网络编程——Socket编程

网络编程的三要素

ip地址:网络中某一台主机的唯一标识
	ipV4: 32位组成,采用点分十进制表示法: 192.168.1.66
	ipV6: 128位组成,采用冒分十六进制表示法: fe80::a0ca:ef4a:766c:62d3%13
	
	ip的命令
		ipconfig: 查看本机的ip地址
		ping 域名/ip地址: 查看网络是否连通
       
端口号:主机上连接网络的应用程序的一个标识(0~65535)

通信协议:数据传输的规则
	UDP:面向无连接的不可靠的协议
	TCP:面向有链接可靠的协议

InetAddress类

在Java语言中使用InetAddress类表示IP地址对象,可以用来获取主机名,主机地址等信息。

public static InetAddress getByName(String host) 
     在给定主机名的情况下确定主机的 IP 地址。 
public String getHostName()
    获取主机名
public String getHostAddress()
    获取主机ip地址
//获取InetAddress对象
InetAddress  address = InetAddress.getByName("127.0.0.1");
//获取主机名
String hostName = address.getHostName();
//获取主机地址
String hostAddress = address.getHostAddress();

UDP发送和接收

发送端

//1.创建DatagramSocket对象
DatagramSocket ds = new DatagramSocket();

//2.创建数据包DatagramPacket对象
byte[] bytes = "你好啊".getBytes(); //需要发送的数据
int length = bytes.length; //数据的长度
InetAddress address = InetAddress.getByName("127.0.0.1"); //对方的ip地址
int port =10086; //对方的端口号
//把前面准备的好数据,以及ip地址,端口号 封装为对象
DatagramPacket dp = new DatagramPacket(bytes,length,address,port);

//3.发送数据包
ds.send(dp);

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

接收端

//1.创建DatagramSocket对象
DatagramSocket ds = new DatagramSocket(10086);

//2.创建数据包DatagramPacet对象
byte[] bs = new byte[1024];
DatagramPacket dp = new DatagramPacket(bs,bs.length);

//3.接收数据,数据会存储到DatagramPacet数据包中
ds.receive(dp);

//4.拆包,获取数据等信息
byte[] data = dp.getData(); //获取字节数组
int length = dp.getLength(); //获取有效的字节个数
InetAddress address = dp.getAddress(); //获取发送端的ip

//把字节数组中有效的部分转换为字符串
String str=new String(data,0,length);
System.out.println(address+"-->"+ str);

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

广播和组播

  • 组播的接收端
//1.创建DatagramSocket对象
MulticastSocket ms = new MulticastSocket(10086);
//把当前主机加入到一组ip
ms.joinGroup(InetAddress.getByName("224.0.1.0"));

//2.创建数据包DatagramPacet对象
byte[] bs = new byte[1024];
DatagramPacket dp = new DatagramPacket(bs,bs.length);

//3.接收数据,数据会存储到DatagramPacet数据包中
ms.receive(dp); //等待发送端发数据

//4.拆包,获取数据等信息
byte[] data = dp.getData(); //获取字节数组
int length = dp.getLength(); //获取有效的字节个数
InetAddress address = dp.getAddress(); //获取发送端的ip

//把字节数组中有效的部分转换为字符串
String str=new String(data,0,length);
System.out.println(address+"-->"+ str);

//5.释放资源
ms.close();
  • 广播的发送端
//1.创建DatagramSocket对象
DatagramSocket ds = new DatagramSocket();

//2.创建数据包DatagramPacket对象
byte[] bytes = "你好啊".getBytes(); //需要发送的数据
int length = bytes.length; //数据的长度
InetAddress address = InetAddress.getByName("255.255.255.255"); //广播地址
int port =10086; //对方的端口号
//把前面准备的好数据,以及ip地址,端口号 封装为对象
DatagramPacket dp = new DatagramPacket(bytes,length,address,port);

//3.发送数据包
ds.send(dp);

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

TCP发送和接收

TCP通信底层是通过IO流来实现的,Socket客户端,ServerSocket服务端。服务端是为客户端提供服务的,需要先开启服务端,然后由客户端过来连接。

在这里插入图片描述

客户端

public class TCPClient {
    public static void main(String[] args) throws IOException {
        //创建Socket对象,连接服务端
        Socket s = new Socket("127.0.0.1", 10010);

        //获取输出流,用来往远程服务器写数据
        OutputStream out = s.getOutputStream();
        out.write("Hello".getBytes());

        //获取输入流,用来读取服务器返回的数据
        InputStream in = s.getInputStream();
        byte[] bs = new byte[1024];
        int len = in.read(bs); //有效的字节是个数
        System.out.println(new String(bs, 0, len));

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

服务端

public class TCPServer {
    public static void main(String[] args) throws IOException {
        //创建ServerSocket对象
        ServerSocket ss = new ServerSocket(10010);
        //监听客户端(迎宾)
        Socket s = ss.accept();
        //获取输入流
        InputStream in = s.getInputStream();
        //读取客户端发过来的数据
        byte[] bs = new byte[1024];
        int len = in.read(bs);
        System.out.println(new String(bs, 0, len));

        //获取输出流
        OutputStream out = s.getOutputStream();
        out.write("你好".getBytes());

        //释放资源
        s.close();
        ss.close();
    }
}

TCP上传图片

在这里插入图片描述

客户端

/*
图片上传的客户端
 */
public class UploadClient {
    public static void main(String[] args) throws IOException {
        //创建Socket对象
        Socket socket = new Socket("127.0.0.1", 10011);
        //获取输出流,用来往服务端写数据
        OutputStream out = socket.getOutputStream(); 

        //读取本地的图片,往服务写
        FileInputStream fis = new FileInputStream("C:\\Users\\itheima\\Desktop\\a.jpg");
        byte[] bs = new byte[1024];
        int len; //记录每次读取的字节个数
        while ((len = fis.read(bs)) != -1) {
            //把读到的数据,通过网络流写到服务器
            out.write(bs, 0, len);
        }
        //写一个结束标记
        socket.shutdownOutput();
        fis.close();

        //获取输入流
        InputStream in = socket.getInputStream();
        //把字节输入流转换为字符输入流
        InputStreamReader isr = new InputStreamReader(in);
        //把字符输入流包装成缓冲流
        BufferedReader br = new BufferedReader(isr);

        //读取服务端返回的数据
        String result = br.readLine();
        System.out.println(result);

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

服务端

/*
图片上传的服务端
 */
public class UploadServer {
    public static void main(String[] args) throws IOException {
        //创建ServerSocket对象
        ServerSocket ss=new ServerSocket(10011);

        while (true){
            //监听客户端
            Socket socket = ss.accept();

            //创建FileOutputStream,用来往服务端本地写数据
            String filename = UUID.randomUUID().toString();
            FileOutputStream fos=new FileOutputStream("C:\\Users\\itheima\\Desktop\\upload\\"+filename+".jpg");

            //获取输入流
            InputStream in = socket.getInputStream();
            byte[] bs=new byte[1024];
            int len;
            while ((len=in.read(bs))!=-1){
                //把读取到的数据,往服务本地的文件中写
                fos.write(bs,0,len);
            }
            fos.close();

            //获取字节输出流
            OutputStream out = socket.getOutputStream();
            //把字节输出流转换为字符输出流
            OutputStreamWriter osw=new OutputStreamWriter(out);
            //把字符输出流包装成缓冲流
            BufferedWriter bw=new BufferedWriter(osw);
            //往客户端回写数据
            bw.write("上传成功");
            bw.newLine();
            bw.flush();

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

        //ss.close();
    }
}

多线程改进服务端

把服务端上传文件的代码写成线程任务,给多个线程共享。

/*
UploadRunnable是用来处理文件上传的任务
是给多个客户端服务的
 */
public class UploadRunnable implements Runnable{

    private Socket socket;
    //创建UploadRunnable对象时,要给Socket赋值
    public UploadRunnable(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        //创建FileOutputStream,用来往服务端本地写数据
        String filename = UUID.randomUUID().toString();
        FileOutputStream fos= null;
        try {
            fos = new FileOutputStream("C:\\Users\\itheima\\Desktop\\upload\\"+filename+".jpg");
            //获取输入流
            InputStream in = socket.getInputStream();
            byte[] bs=new byte[1024];
            int len;
            while ((len=in.read(bs))!=-1){
                //把读取到的数据,往服务本地的文件中写
                fos.write(bs,0,len);
            }
            fos.close();

            //获取字节输出流
            OutputStream out = socket.getOutputStream();
            //把字节输出流转换为字符输出流
            OutputStreamWriter osw=new OutputStreamWriter(out);
            //把字符输出流包装成缓冲流
            BufferedWriter bw=new BufferedWriter(osw);
            //往客户端回写数据
            bw.write("上传成功");
            bw.newLine();
            bw.flush();

            InetAddress address = this.socket.getInetAddress();
            System.out.println(address+"上传了一张图片");

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //释放资源
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 每次监听到客户端连接服务器,就开启一条线程
public static void main(String[] args) throws IOException {
    //创建ServerSocket对象
    ServerSocket ss=new ServerSocket(10011);

    while (true){
        //监听客户端
        Socket socket = ss.accept();
        //给Socket客户端,单独开线程
        new Thread(new UploadRunnable(socket)).start();
    }
    //ss.close();
}
  • 线程池改进服务端
/*
图片上传的服务端
 */
public class UploadServer {
    public static void main(String[] args) throws IOException {
        //创建ServerSocket对象
        ServerSocket ss = new ServerSocket(10011);
		//创建线程池
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
                6, //核心线程数
                9, //最大线程数
                3, //空闲时间
                TimeUnit.SECONDS, //时间单位:秒
                new ArrayBlockingQueue<>(10),
                Executors.defaultThreadFactory(), //默认的工厂对象,由工厂对象帮我们生产线程
                new ThreadPoolExecutor.AbortPolicy() //拒绝的方式
        ); 

        while (true) {
            //监听客户端
            Socket socket = ss.accept();
            //给Socket客户端,单独开线程
            poolExecutor.submit(new UploadRunnable(socket));
        }

        //ss.close();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值