铂西学习日记---TCP实现ECHO(应答)程序

本文介绍了TCP和UDP两种传输协议的基础知识,包括它们在数据帧格式中的区别。通过 Echo 程序展示了TCP和UDP的简单通信,并实现了多线程服务器处理多个客户端连接。此外,还探讨了客户端之间通过服务器进行通信的实现,涉及到了消息类型的定义和序列化。
摘要由CSDN通过智能技术生成

TCP: ( Transmission Control Protocol) 传输控制协议,采用三方握手的方式,保证准确的连接操作。
UDP: (User Datagram Protocol) 数据报协议,发送数据报,例如:手机短信或者是QQ消息。
TCP、UDP的数据帧格式简单关系(其中协议类型用于区分TCP、UDP):
协议类型源IP  |  目标P  |  源端口目标端口  |  帧序号  |  帧数据
 

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

 服务端

package echo;

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

public class ServerDemo {
    public static void main(String[] args) {
        /**
         * 创建一个服务端的Socket(1024-15535)
         */
        try {
            ServerSocket serverSocket = new ServerSocket(6666);
            System.out.println("服务器已启动,正在等待客户端的链接...");
            //等待客户端的链接,造成阻塞,如果有客户端连接成功就返回一个Socket对象
            Socket socket = serverSocket.accept();
            System.out.println("建立连接成功--->"+socket.getLocalAddress());
            /**
             * IO传输
             */
            //通过输入流读取网络数据,
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String str = br.readLine();//在此处,如果没有数据就会造成阻塞
            System.out.println("数据获取成功!");
            //获取输出流,向客户端返回消息
            PrintStream ps = new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
            ps.print("Echo:"+str);
            ps.flush();
            System.out.println("数据已返回客户端!");
            //关闭流
            br.close();
            ps.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 客户端

package echo;

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

public class ClientDemo {
    public static void main(String[] args) {
        /**
         * 创建一个Socket对象,指定一个服务器对象
         */
        try {
            Socket socket = new Socket("127.0.0.1",6666);

            /**
             * IO传输
             */
            //获取Socket的输入输出流
            PrintStream ps = new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //传输的消息
            ps.println("Hello Socket!");
            ps.flush();
            //从服务端接受到的消息
            String str = br.readLine();
            System.out.println(str);
            //关闭流
            ps.close();
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 结果:

 

应答程序多线程实现,能让一个服务器处理多个客户端 

服务端: 

package echo;

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

//处理多个客户端信息
//主线程用来监听线程的连接,每次有连接成功就让线程池中的线程去处理任务
public class MultipleServerDemo {
    public static void main(String[] args) {
        //线程池
        ExecutorService es = Executors.newFixedThreadPool(3);
        try {
            ServerSocket serverSocket = new ServerSocket(6666);
            System.out.println("服务器已启动!正在等待连接...");
            //反复接受多个客户端的请求
            while (true){
                Socket s = serverSocket.accept();
                System.out.println(s.getLocalAddress());
                es.execute(new UserThread(s));
            }
        } 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();
            br.close();
            ps.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户端:

package echo;

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

public class MultipleClientDemo {
    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);

        /**
         * 创建一个Socket对象,指定一个服务器对象
         */
        try {
            Socket socket = new Socket("127.0.0.1",6666);

            /**
             * IO传输
             */
            //获取Socket的输入输出流
            PrintStream ps = new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //传输的消息
            System.out.println("请输入消息:");
            String info = scanner.nextLine();
            ps.println(info);
            ps.flush();
            //从服务端接受到的消息
            info = br.readLine();
            System.out.println(info);
            //关闭流
            ps.close();
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户端与客户端之间的通信 ,即服务器端用于转发通信

 MgsType类

package clientToClient;

public final class MgsType {
    public static final int LOGIN = 0x1;//登录消息类型
    public static final int MSG = 0x2;//发送消息类型
}

 Message类

package clientToClient;

import java.io.Serializable;

public class Message implements Serializable {//继承可序列化
    private String from;//谁发的
    private String to;//发给谁
    private int type;//消息类型
    private String info;//消息内容

    public Message() {
    }

    public Message(String from, String to, int type, String info) {
        this.from = from;
        this.to = to;
        this.type = type;
        this.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;
    }
}

Client类

package clientToClient;

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

public class Client {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        ExecutorService es = Executors.newSingleThreadExecutor();//单个线程

        try {
            Socket socket = new Socket("127.0.0.1",8911);
            System.out.println("与服务器建立连接成功");

            //流
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());//写
            ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());//读

            System.out.println("请输入名称:");
            String name = sc.nextLine();
            Message msg = new Message(name, null, MgsType.LOGIN, null);
            oos.writeObject(msg);

            msg = (Message) ois.readObject();
            System.out.println(msg.getFrom()+msg.getInfo());

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

            //使用主线程发送消息
            while (true){
                msg = new Message();
                System.out.println("To:");
                msg.setTo(sc.nextLine());
                msg.setFrom(name);
                msg.setType(MgsType.MSG);
                System.out.println("Info:");
                msg.setInfo(sc.nextLine());
                oos.writeObject(msg);
            }

        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}

class SendMsgByClient implements Runnable{
    private ObjectInputStream ois;//读取
    private boolean flag = true;

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

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

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

Server类

package clientToClient;

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 es = Executors.newFixedThreadPool(3);//可最大连接3个客户端

        //创建服务器
        try {
            ServerSocket ss = new ServerSocket(8911);
            System.out.println("服务器已开启,正在等待连接...");
            while (true){
                Socket socket = ss.accept();
                UserThread user = new UserThread(socket, vector);
                es.execute(user);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }


    }
}

/**
 * 客户端处理的线程
 */
class UserThread implements Runnable{
    private String name;//用于记录客户端的名字
    private Socket socket;//客户端的socket
    private Vector<UserThread> vector;//客户端处理线程的集合
    //流
    private ObjectInputStream ois;
    private ObjectOutputStream oos;
    private boolean flag = true;

    public UserThread(Socket socket,Vector vector){
        this.socket = socket;
        this.vector = vector;
        //将这个线程添加到集合中
        vector.add(this);
    }

    @Override
    public void run() {
        System.out.println("客户端-->"+socket.getLocalAddress()+"已连接!");//通知已连接
        try {
            //流的对象
            oos = new ObjectOutputStream(socket.getOutputStream());
            ois = new ObjectInputStream(socket.getInputStream());

            //读取消息对象
            while (flag) {
                Message msg = (Message) ois.readObject();
                int type = msg.getType();

                switch (type){
                    case MgsType.MSG:
                        int size = vector.size();//待会从集合中遍历找出发送对象
                        String to = msg.getTo();//发送给谁的
                        UserThread ut;
                        for (int i=0;i<size;i++){
                            ut = vector.get(i);
                            if(to.equals(ut.name) && ut!=this){
                                ut.oos.writeObject(msg);
                                break;
                            }
                        }
                        break;
                    case MgsType.LOGIN:
                        name = msg.getFrom();
                        msg.setInfo("欢迎您!");
                        oos.writeObject(msg);
                        break;
                }
            }
            //关闭流
            ois.close();
            oos.close();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}

结果:

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小狗铂西

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值