#java 聊天室(一)—— 实现一个简单Telnet多人群聊聊天室

#java    聊天室(一)——  实现一个简单Telnet多人群聊聊天室

 

学习本文需要先准备的知识点:队列(或数组)、类与对象、线程、InputStream和OutputStream的使用。

1.前期准备(新知识点讲解)

(1)、认识Telnet

a、关于Telnet

Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的能力。在终端使用者的电脑上使用telnet程序,用它连接到服务器。终端使用者可以在telnet程序中输入命令,这些命令会在服务器上运行,就像直接在服务器的控制台上输入一样。可以在本地就能控制服务器。要开始一个telnet会话,必须输入用户名和密码来登录服务器。Telnet是常用的远程控制Web服务器的方法。

b、telnet的工作过程:

(a)、本地与远程主机建立连接。该过程实际上是建立一个TCP连接,用户必须知道远程主机的Ip地址或域名;

(b)、将本地终端上输入的用户名和口令及以后输入的任何命令或字符以NVT(Net Virtual Terminal)格式传送到远程主机。该过程实际上是从本地主机向远程主机发送一个IP数据包;

(c)、将远程主机输出的NVT格式的数据转化为本地所接受的格式送回本地终端,包括输入命令回显和命令执行结果;

(d)、最后,本地终端对远程主机进行撤消连接。该过程是撤销一个TCP连接。

(以上关于telnet的内容摘自百度百科)

    我们需要做的,就是写一个服务器,使用户能够连接上我们的服务器,而且我们的服务器能够对用户发送的消息进行处理

(2)、BufferedReader类:用于从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。此类的对象创建时,需要传入一个InputStream对象

此类的部分相关方法:

read();  // 读取单个字符。
readLine(); //读取一个文本行,程序运行到这里时需要用户输入,将用户输入的数据读取。

例如:

bs = new BufferedReader(new InputStreamReader(in));
String name = bs.readLine();

(3)、ServerSocket类:此类实现服务器套接字。服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果。简而言之,就是在指定端口创建一个服务器此类的对象创建时,需要传入的数字就是端口

       此类的相关方法:

accept();  //侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞。即接受用户连接,在用户未连接时程序会在此暂停。其返回值是一个Socket对象。

例如:

//在6666端口创建一个服务器,等待用户连接(虽然创建了,但不会对用户的连接作出反应)。
ServerSocket sever = new ServerSocket(6666);Socket sk = sever.accept();

(4)、Socket类:此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。 可以利用Socket对象与客户端进行交互。

       此类的相关方法:

getOutputStream();  //返回此套接字的输出流。即返回用户端的输出流,可以借助此输出流显示传递给用户的信息。
getInputStream();  //返回此套接字的输入流。即返回用户端的输入流,可以借助此输入流获取用户端的输入信息。

 

2.思路分析

(1)、建立一个服务器,实现相应的端口,在用户连接的时候启动一个线程,用于获取用户的输入和输出,为了能够让多个用户连接,可以将侦听用户连接的代码放在一个while(true)循环里面(侦听的语句在没有用户连接的时候会在此暂停,不用担心死循环造成的程序卡顿等问题):

//建立一个Message对象的队列,用于储存用户的信息,Message对象将会在后面介绍
static ArrayList<Message> m = new ArrayList<>();
static ServerSocket sever;
	public static void main(String[] args) {
		try {
//创建一个服务器,实现6666端口
			sever = new ServerSocket(6666);
			System.out.println("服务器已开启。");
			while (true) {
                             //侦听用户连接,没有用户连接的时候会在此停留
				Socket sk = sever.accept();
                             //有用户连接,创建一个线程控制用户的输入输出
				Sever ss = new Sever(m,sk);
				Thread ts = new Thread(ss);
                             //启动线程
				ts.start();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

(2)、建立一个对象,储存用户输入的信息,并且执行改用户的输出操作

public class Message {
       //msg用于储存用户输入的消息
	private String msg;
       //name储存用户姓名
	private String name;
       //判断用户有没有输入
	private boolean isNewPut = true;
       //判断用户是不是第一次进入
	private boolean isNewJoin = true;
       //用于控制线程的开始停止
	private boolean start = true;

	public void setName(String name) {
		this.name = name;
	}
	
	public boolean getStart() {
		return start;
	}

	public String getName() {
		return name;
	}

	public Message() {
		msg = new String();
	}

       //获取用户输入的信息,将判断是否有用户输入的boolean值改为true,这个值为true时,下面介绍的的Together线程将会向所有用户输出此用户的消息
	public void addMsg(String msg) {
		this.msg = msg;
		isNewPut = true;
	}

	public String getMsg() {
		return msg;
	}

	public void setIsNewPut(boolean s) {
		isNewPut = s;
	}

	public boolean getIsNewPut() {
		return isNewPut;
	}

	public void setIsNewJoin(boolean j) {
		isNewJoin = j;
	}

	public boolean getIsNewJoin() {
		return isNewJoin;
	}

       //用户退出时,将strat、isNewPut改成false
	public void exit() {
		start = false;
		isNewPut = false;
	}
}

(3)、编写控制用户输入输出的线程

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;

public class Sever implements Runnable {
        //用于储存用户的Message队列
	private ArrayList<Message> msg;
       	private Socket sk;
	private Message m;
        //count可用作区分用户的索引
	private int count;
	private OutputStream out;
	private BufferedReader bs;
	private InputStream in;

	public Sever(ArrayList<Message> msg, Socket sk, int count) {
		this.msg = msg;
		this.sk = sk;
		this.count = count;
	}

	public void run() {
		recieve();
 	}

        //将用户的输出传给所有用户,并在所有用户的控制台输出
	public void setMsg(BufferedReader bs) throws IOException {
		while (msg.get(count).getStart()) {
			String strMsg = bs.readLine();
			if (strMsg != null)
				msg.get(count).setMsgAll(msg.get(count).getName() + " said:" + strMsg + "\r\n");
		}
	}

        //接受用户输入并处理
	public void recieve() {
		try {
                        //获取用户控制台的输入输出流
			out = sk.getOutputStream();
			in = sk.getInputStream();
			out.write("welcome!Please enter your username:\r\n".getBytes());
			bs = new BufferedReader(new InputStreamReader(in));
                        //获取用户输入,如果用户没有按回车,程序会在此暂停
			String name = bs.readLine();
			out.write(("Your username is:" + name + "\r\n").getBytes());
                        //初始化Message对象,并将用户的姓名、输出流、消息储存进用户的Message对象
			m = new Message(name, out, msg);
                        //用于区分用户的索引,比如第一个用户登录时这个值为0,第二个用户时这个值为2
			count = msg.size();
                        //将Message对象m存入Message队列的第count处
			msg.add(count, m);
                        //在所有用户的控制台输入XXX已经上线
			msg.get(count).setMsgAll(name + " is on line.\r\n");
                        //此函数会循环获取用户输入并在所有用户的控制台输出
			setMsg(bs);
                        //跳出上面的函数说明用户已经下线,则关闭所有的流、用户对应的Socket对象,从Message队列移除上线的用户
			out.close();
			in.close();
			sk.close();
			msg.remove(count);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

 

  • 11
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值