【Java基础25】网络编程,协议,客户端通信,URL,MINA框架

一、网络编程的概念

网络编程主要是完成C/S程序的开发(client/server,客户端/服务器)。

C/S:开发两套程序,两套程序同时需要维护,例如QQ,一般比较稳定。

B/S(browser/server,浏览器/服务器):开发一套程序,客户端使用浏览器进行访问,一般稳定性和安全性较差。

二、网络编程TCP协议

TCP是一个可靠的协议,面向连接的协议,实现TCP协议,需要编写服务器和客户端,java.net包为实现网络应用程序提供类。

ServerSocket:此类实现服务器套接字。

Socket:此类实现客户端套接字。

Socket是网络驱动层提供给应用程序编程的接口和一种机制。

三、TCP实现Echo程序

Echo,意为应答,程序的功能是客户端向服务器发送一个字符串,服务器不做任何处理,直接把字符串返回给客户端,Echo程序是最为基本的客户/服务器程序。

//TCP先启动服务器端,再启动客户端。

//服务器端
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class EchoServer {
    //实现echo程序
    public static void main(String[] args) {
        //创建一个服务器端的Socket(端口1024-65535)
        try {
            ServerSocket ss=new ServerSocket(6666);
            System.out.println("服务器已启动,正在等待客户端的连接....");
            //等待客户端的连接,造成阻塞,如果有客户端连接成功,就会立即返回一个Socket对象
            Socket accept = ss.accept();
            System.out.println("客户端连接成功!"+ss.getInetAddress().getHostAddress());
            BufferedReader br =new BufferedReader
                    (new InputStreamReader(accept.getInputStream()));
            //通过输入流来读取网络数据,如果没有数据会阻塞
            String s = br.readLine();
            System.out.println(s);
            //获取输出流,向客户端返回消息
            PrintStream ps=new PrintStream(new BufferedOutputStream(accept.getOutputStream()));
            ps.println("echo:"+s);
            ps.flush();
            //关闭
            ps.close();
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

//客户端
import java.io.*;
import java.net.Socket;

public class EchoClient {
    public static void main(String[] args) {
        //创建一个Socket对象,指定要连接的服务器
        try {
            Socket socket = new Socket("localhost",6666);
            //获取socket的输入输出流
            PrintStream ps=new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
            BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
            ps.println("12345678");
            ps.flush();
            //读取服务器端返回的数据
            String info=br.readLine();
            System.out.println(info);
            ps.close();
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

四、服务器与多客户端通信

引入线程,用不同的线程对应不同的客户端。

//服务器端
import com.sun.corba.se.spi.activation.Server;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//主线程用于监听客户端的连接,每次有连接成功,开启一个线程来连接该客户端的消息
public class MultiServer {
    //同时处理多个客户端
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        try {
            ServerSocket ss=new ServerSocket(6666);
            System.out.println("服务器已启动,正在等待连接...");
            while (true){
                Socket accept = ss.accept();
                System.out.println(accept.getInetAddress().getHostAddress());
                executorService.execute(new UserThread(accept));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
//处理客户端请求的线程
class UserThread implements Runnable{
    private Socket s;

    public UserThread(Socket s) {
        this.s = s;
    }

    @Override
    public void run() {
        try {
            BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
            PrintStream ps=new PrintStream(new BufferedOutputStream(s.getOutputStream()));
            String s = br.readLine();
            System.out.println(s);
            ps.println("echo:"+s);
            ps.flush();
            ps.close();
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

//客户端
import java.io.*;
import java.net.Socket;
import java.util.Scanner;

public class MUltiClient {
    public static void main(String[] args) {
        Scanner scan=new Scanner(System.in);
        //创建一个Socket对象,指定要连接的服务器
        try {
            Socket socket = new Socket("localhost",6666);
            //获取socket的输入输出流
            PrintStream ps=new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
            BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
            System.out.println("请输入:");
            String s = scan.nextLine();
            ps.println(s);
            ps.flush();
            //读取服务器端返回的数据
            s=br.readLine();
            System.out.println(s);
            ps.close();
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

五、多客户端之间的通信

通过服务器进行中转,发送一个数据包。

//服务器端
package communication;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Server {
    public static void main(String[] args) {
        //集合,保存客户端处理的线程
        Vector<UserThread> vector=new Vector<>();
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        //创建服务器端的Socket
        try {
            ServerSocket ss=new ServerSocket(6666);
            System.out.println("服务器已启动,正在等待连接...");
            while(true){
                Socket accept = ss.accept();//接收
                UserThread ut=new UserThread(accept,vector);
                executorService.execute(ut);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

//客户端处理的线程
class UserThread implements Runnable{
    private String name;//客户端名称
    private Socket s;
    Vector<UserThread> vector;//客户端处理线程的集合
    public ObjectInputStream ois;
    private ObjectOutputStream oos;
    private boolean flag=true;
    public UserThread(Socket s, Vector<UserThread> vector) {
        this.s=s;
        this.vector=vector;
        vector.add(this);
    }

    @Override
    public void run() {
        System.out.println("客户端"+s.getInetAddress().getHostAddress()+"已连接");
        try {
            ois=new ObjectInputStream(s.getInputStream());
            oos=new ObjectOutputStream(s.getOutputStream());
            while(flag){
                //读取消息对象
                Message m=(Message) ois.readObject();
                int type=m.getType();
                switch (type){
                    case MessageType.TYPE_SEND:
                        String to = m.getTo();
                        UserThread userThread;
                        int size = vector.size();
                        for (int i = 0; i < size; i++) {
                            userThread=vector.get(i);
                            if(to.equals(userThread.name)&&userThread!=this){
                                userThread.oos.writeObject(m);
                                break;
                            }
                        }
                        break;

                    case MessageType.TYPE_LOGIN:
                        name=m.getFrom();
                        m.setInfo("欢迎您");
                        oos.writeObject(m);
                        break;
                }
            }
            oos.close();
            ois.close();
        } catch (IOException|ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}

//客户端
package communication;

import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Client {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        try {
            Socket s=new Socket("localhost",6666);
            System.out.println("服务器连接成功");
            ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream());
            ObjectInputStream ois=new ObjectInputStream(s.getInputStream());
            //向服务器发送登录信息
            System.out.println("请输入名称:");
            String name = scanner.nextLine();
            Message m=new Message(name,null,MessageType.TYPE_LOGIN,null);
            oos.writeObject(m);
            m=(Message) ois.readObject();
            System.out.println(m.getInfo()+m.getFrom());

            //启动读取消息的线程
            executorService.execute(new ReadIndoRunnable(ois));

            //使用主线程来发送消息
            boolean flag=true;
            while (flag){
                m= new Message();
                System.out.println("To:");
                m.setTo(scanner.nextLine());
                m.setFrom(name);
                m.setType(MessageType.TYPE_SEND);
                System.out.println("InFo:");
                m.setInfo(scanner.nextLine());
                oos.writeObject(m);
            }
        } catch (IOException|ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}
//读取消息的线程
class ReadIndoRunnable implements Runnable{
    private ObjectInputStream ois;
    private boolean flag=true;

    public ReadIndoRunnable(ObjectInputStream ois) {
        this.ois = ois;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public void run() {
        try {
            while (flag) {
                Message message = (Message) ois.readObject();
                System.out.println("[" + message.getFrom() + "]" + "对我说 " + message.getInfo());
            }
            if(ois!=null){
                ois.close();
            }
        }catch (IOException | ClassNotFoundException e) {
                    e.printStackTrace();
        }

    }
}

//消息类型
package communication;

public class MessageType {
    public static final int TYPE_LOGIN=0x1;//登录消息类型
    public static final int TYPE_SEND=0x2;//发送消息类型
}

//消息
package communication;

import java.io.Serializable;

//消息包
public class Message implements Serializable {
    private String from;//发送者
    public String to;//接收者
    private int type;//消息类型
    private String info;//消息

    @Override
    public String toString() {
        return "Message{" +
                "from='" + from + '\'' +
                ", to='" + to + '\'' +
                ", type=" + type +
                ", info='" + info + '\'' +
                '}';
    }

    public String getFrom() {
        return from;
    }

    public void setFrom(String from) {
        this.from = from;
    }

    public String getTo() {
        return to;
    }

    public void setTo(String to) {
        this.to = to;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }

    public Message(String from, String to, int type, String info) {
        this.from = from;
        this.to = to;
        this.type = type;
        this.info = info;
    }

    public Message() {
    }
}

六、网络编程UDP协议

无连接,不可靠的协议。传输的数据报在64KB之内。

DatagramPacket:此类表示数据报包。

DatagramSocket:此类表示用来发送和接收数据报的套接字。

//UDP先运行客户端 等待传输数据,再运行服务器端 传输数据  

//服务端
import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;

public class UDPServer {
    public static void main(String[] args) {
        String info="good good study,天天向上";
        byte[] b=info.getBytes(StandardCharsets.UTF_8);
        try {
            //封装一个数据报包
            DatagramPacket dp=new DatagramPacket(
                    b,
                    0,
                    b.length,
                    InetAddress.getByName("127.0.0.1"),
                    8000);
            //本程序的端口
            DatagramSocket ds=new DatagramSocket(9000);
            ds.send(dp);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

//客户端
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class UDPClient {
    public static void main(String[] args) {
        byte[] b=new byte[1024];
        DatagramPacket dp=new DatagramPacket(b,b.length);
        try {
            DatagramSocket ds=new DatagramSocket(8000);
            System.out.println("正在接收数据中...");
            ds.receive(dp);//接收数据
            String s = new String(dp.getData(), 0, dp.getLength());
            System.out.println(s);
            ds.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

七、URL

URL(统一资源定位符),是指向互联网“资源”的指针,抽象类URLConnection是所有类的超类,它代表应用程序和URL之间的通信链接。

网址就是一个URL。

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;

public class URL {


    public URL(String s) {

    }

    public static void main(String[] args) {
       //互联网上每个文件都有一个唯一的URL
        try {
            URL u=new URL("https://blog.csdn.net/weixin_54068678?spm=1000.2115.3001.5343");
            HttpURLConnection httpURLConnection = (HttpURLConnection) u.openConnection();

            BufferedInputStream bi=new BufferedInputStream(httpURLConnection.getInputStream());
            BufferedOutputStream bo=new BufferedOutputStream(new FileOutputStream("E:\\ideaWorkplace\\0401"));
            byte[] b=new byte[1024];
            int len=-1;
            while((len=bi.read(b))!=-1){
                bo.write(b,0,len);
                bo.flush();
            }
            bi.close();
            bo.close();
            System.out.println("下载成功");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private Object openConnection() {
        return null;
    }


}

八、MINA框架

一个简洁易用的基于TCP/IP通信的Java框架

下载地址:https://mina.apache.org/

开发一个MINA应用:创建连接,设定过滤规则,编写自己的消息处理器

具体参考其他网页。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值