第1部分 TCP和UDP

TCP:是一种可靠地传输协议,是把消息按一个个小包传递并确认消息接收成功和正确才发送下一个包,速度相对于UDP慢,但是信息准确安全;常用于一般不要求速度和需要准确发送消息的场合。

UDP:是一种不可靠的传输协议,常用于视频直播、游戏等及时性比较强的场景。

进行相关编程可以查询API手册。

第2部分 多人聊天室

下面是利用Java的TCP协议的API实现多人聊天室的案例代码:

服务端:

运行在服务端的SeverSocket主要负责:

1 向系统申请服务端口号,客户端是通过这个端口号和IP地址与之连接的;端口号一般取四千之一万之间,因为其余有的已经绑定系统系统应用和主流应用程序,最常用的便是8088。

2 监听申请的服务端口号,当一个客户端通过该端口号尝试建立联系连接时,SeverSocket会在服务端创建一个Socket与客户端建立连接,服务端正对不同客户端建立多个Socket,利用多线程实现。

工作模块及过程:

服务器先初始化,包括申请端口号,和创建共享消息集合(可以用map,key是用户名,value是消息,私聊返回value值,广播则遍历value),另外创建增删和发送消息的方法;

创建处理客户端交互的类,继承runnable,通过socket的getInetAdress和getHostAdress方法获取客户端计算机的信息,其start方法用来完成从一个客户端接收消息,并将其他客户端的消息返回给该客户端;

package chat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List; /**
*
* 运行在服务端的SeverSocket主要负责;
* 1 向系统申请服务端口号客户端是通过这个端口号与之连接的
* 2 监听申请的服务端口号,当一个客户端通过该端口号尝试建立联系连接时,
* SeverSocket会在服务端创建一个Socket与客户端建立连接
* 服务端正对不同客户端建立多个Socket
*
* @author KwinWei QQ:885251358
*
*/
public class Server { public ServerSocket server;
/*
* 用来保存客户端输出流的集合,
*因为线程安全的也不和遍历互斥,要自己维护也可以保证安全
*/
private List<PrintWriter> allOut; //私聊可以用map,key为昵称,value是对应消息,广播则遍历value /*
*初始化 服务端
*/
public Server()throws Exception {
/*
* 初始化的同时申请端口号
*/
server = new ServerSocket(8788);
allOut = new ArrayList<PrintWriter>();
} /**
* 将给定的输出流存入共享集合
* @param out
*/
private synchronized void addOut(PrintWriter out) {
allOut.add(out);
}
/**
* 将给定的输出流从共享集合中删除
* @param out
*/
private synchronized void removeOut(PrintWriter out) {
allOut.remove(out);
}
/**
* 将给定的消息发送给所有客户端
* @param out
*/
private synchronized void sendMessage(String message) {
for(PrintWriter out : allOut) {
out.println(message);
}
} /*服务端开始工作的方法
*
*/
public void start() {
try {
/*
* ServerSocket的accept的方法
* 是一个阻塞的方法,作用是监听服务端口号,知道一个客户端;连接并创建一个Socket,使用该Socket
* 即可与刚才链接的客户端进行交互
*/ while(true) {
System.out.println("等待客户端连接...");
Socket socket = server.accept();
System.out.println("一个客户端连接了!"); /*
* 启动一个线程,来完成与该客户端的交互
*/
ClientHandler handler= new ClientHandler(socket);
Thread t = new Thread(handler);
t.start();
}
} catch (Exception e) {
e.printStackTrace();
} }
public static void main(String[] args) {
try {
Server server = new Server();
server.start();
} catch (Exception e) {
e.printStackTrace();
System.out.println("服务端建立联系失败!");
}
} /**
*该线程负责处理一个客户端的交互
*
*/
class ClientHandler implements Runnable{
/*
* 该线程处理的客户端的Socket
*/
private Socket socket ; // 客户端的地址信息,区分不同客户端
private String host; //用户的昵称
private String nickName; public ClientHandler(Socket socket) {
this.socket = socket;
/*
* 通过Socket可以获取远端计算机的地址信息
*/
InetAddress address = socket.getInetAddress();
//获取IP地址
host = address.getHostAddress();
}
public void run() {
PrintWriter pw = null;
try { /*
* Socket 提供的方法
* InputStream getInputStream()
* 该方法可以获取一个输入流,从该方法读取的数据就是从远端计算机发送来的
*/
InputStream in = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(in,"UTF-8");
BufferedReader br = new BufferedReader(isr); //首先读取一行字符串为昵称
nickName = br.readLine();
//System.out.println(host+"上线了");
sendMessage(nickName+"上线了"); /*
* 通过Socket创建输出流用于将消息发送给客户端
*/
OutputStream out = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(out,"UTF-8");
pw = new PrintWriter(osw,true); /*
* 将该客户端对的输出流存入到共享集合中
*/
addOut(pw); String message = null;
/*
* br.readLine()在读取客户户端发送过来的消息时,由于客户端断线,
* 而操作系统的不同,这里读取后的结果不同:
* 当windows的客户端断开时:br.readLine会抛出异常
* 当linux的客户端断开时:br.readLine 会返回null
*/ while((message = br.readLine())!=null) {
//System.out.println(host+"说:"+ message);
//pw.println(host+"说:"+message);
//广播消息
sendMessage(nickName+"说:"+message);
} } catch (Exception e) { }finally {
/*
* 处理当前客户端断开后的逻辑
*/
//将该客户端的输出流从共享集合中删除
removeOut(pw);
//System.out.println(host+"下线了");
sendMessage(nickName+"下线了");
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} } }

客户端:

package chat;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner; /**
*
* @author KwinWei QQ:885251358
*
*/
public class Client {
/*
* 套接字
*
* 理解为电话,拨号,建立联系,麦克风说话,
* socket输入和输出流,
* 你输入流对应他输出流,你说话他听
* 你输出流对应他输入流
*
* java,net.Socket;
* 封装了TCP协议,使用它就可以基于某种TCP协议进行网络通信
* Socket试运行在客户端的
*/
private Socket socket; public Client() throws Exception {
/*
*实例化Socket的时候需要传入两个参数
* 1 IP:127.0.0.1或localhost本机;
* 2 端口:0-65535,听服务端的,区用网程序,
* 一般使用四千以上一万以下,前四千被占用绑定主流应用程序等
* 通过Ip可以找到服务的那台计算机,通过端口号可以找到服务端计算机上服务端用程序
*
* 实例化Socket的过程就是连接的过程,若远端计算机没有响应会抛出异常
*
*/
System.out.println("正在连接服务端...");
socket = new Socket("localhost",8788);
System.out.println("已经和服务端建立联系");
} /*
* 启动客户端的方法
*/
public void start() {
try {
Scanner scanner = new Scanner(System.in);
/*
* 先要求用户创建一个昵称
*/
//System.out.println("");
String nickName = null;
while(true) {
System.out.println("请用户输入用户名");
nickName = scanner.nextLine();
if(nickName.length()>0) {
break;
}
System.out.println("输入有误");
}
System.out.println("欢迎你"+nickName+"!开始聊天吧!");
/*socket 提供的方法:
* OutputStream getOutStream
* 获取一个字节输出流,通过该流写出的数据会被发送至远端计算机。
*/
OutputStream out = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(out,"UTF-8");
PrintWriter pw = new PrintWriter(osw,true); //不能指明字节流,所以要加一个转换流,第二参数为true会行刷新 //先将昵称发给服务器 pw.println(nickName); /*
* 启动读取服务端发送过来消息的线程
*/
ServerHandler handler = new ServerHandler();
Thread t = new Thread(handler);
t.start(); /*
* 将字符串发送至服务端,加上行刷新,说一句发一句
* 否则需要用 flush()强制写出
*/
while(true) {
pw.println(scanner.nextLine());
//pw.flush(); }
} catch (Exception e) {
e.printStackTrace();
} } public static void main(String[] args) {
try {
Client client = new Client();
client.start();
}catch(Exception e) {
e.printStackTrace();
System.out.println("客户端启动失败!");
}
} /*
* 该线程用来读取服务器端发送来的消息,并输出到客户端控制台显示
*/
class ServerHandler implements Runnable {
public void run() {
try {
InputStream in = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(in,"UTF-8");
BufferedReader br = new BufferedReader(isr); String message = null;
while ((message = br.readLine())!=null) {
System.out.println(message);
} } catch (Exception e) { }
}
} }

多人聊天室(Java)的更多相关文章

  1. java socket之多人聊天室Demo

    一.功能介绍 该功能实现了一个类似QQ的最简单多人聊天室,如下图所示. 二.目录结构 三.服务端 1)SocketServer类,该类是服务端的主类,主要负责创建聊天窗口,创建监听客户端的线程: pa ...

  2. java小程序---简陋版多人聊天室

    功能需求: 1 每运行一次主函数,创建一个客户端聊天界面; 2 客户端界面分三块,公屏(显示所有客户端发送的信息),私屏(用于输入个人想要发送的信息),发送按钮(点击一次,将客户端信息发送到服务端) ...

  3. Apache MiNa 实现多人聊天室

    Apache MiNa 实现多人聊天室 开发环境: System:Windows JavaSDK:1.6 IDE:eclipse.MyEclipse 6.6 开发依赖库: Jdk1.4+.mina-c ...

  4. Spring整合DWR comet 实现无刷新 多人聊天室

    用dwr的comet(推)来实现简单的无刷新多人聊天室,comet是长连接的一种.通常我们要实现无刷新,一般会使用到Ajax.Ajax 应用程序可以使用两种基本的方法解决这一问题:一种方法是浏览器每隔 ...

  5. 66 网络编程(五)——TCP多线程实现多人聊天室

    思路 客户端读写各一个类,可以使内部类,实现Runnable.读写类都与服务器端建立连接,一个收,一个发. 客户端实现接收和转发.多线程实现每个客户端的连接(使与各客户端的连接独立). 服务器端中创建 ...

  6. 与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室

    原文:与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...

  7. 与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室

    原文:与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...

  8. 使用Go语言+Protobuf协议完成一个多人聊天室

    软件环境:Goland Github地址 一.目的 之前用纯逻辑垒完了一个可登入登出的在线多人聊天室(代码仓库地址),这次学习了Protobuf协议,于是想试着更新下聊天室的版本. 主要目的是为了掌握 ...

  9. 基于tcp和多线程的多人聊天室-C语言

    之前在学习关于网络tcp和多线程的编程,学了知识以后不用一下总绝对心虚,于是就编写了一个基于tcp和多线程的多人聊天室. 具体的实现过程: 服务器端:绑定socket对象->设置监听数-> ...

随机推荐

  1. nmap比较详细的使用方法

    nmap 信息收集工具 -sP 192.168.1.0/24  区域网内存活主机扫描  -O 192.168.1.1    获取操作系统 nmap -sS -sV baidu.com    -sS 使 ...

  2. linux 本机内核模块

    make -C /lib/modules/4.13.0-36-generic/build M=/$(pwd) modules 内核里只需要写obj-m:=hello.o

  3. Hystrix是个什么玩意儿

    1. 什么是Hystrix Hystrix是Netflix的一个开源框架,地址如下:https://github.com/Netflix/Hystrix 中文名为“豪猪”,即平时很温顺,在感受到危险的 ...

  4. 【入门】Spring-Boot项目配置Mysql数据库

    前言 前面参照SpringBoot官网,自动生成了简单项目点击打开链接 配置数据库和代码遇到的问题 问题1:cannot load driver class :com.mysql.jdbc.Drive ...

  5. Loj #3056. 「HNOI2019」多边形

    Loj #3056. 「HNOI2019」多边形 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时针方向标号依次为 \(1,2,3, \ldots , n\).最开 ...

  6. springboot中配置过滤器以及可能出现的问题

    在springboot添加过滤器有两种方式: 1.通过创建FilterRegistrationBean的方式(建议使用此种方式,统一管理,且通过注解的方式若不是本地调试,如果在filter中需要增加c ...

  7. ubuntu系统下mysql重置密码和修改密码操作

    一.忘记密码后想重置密码 在介绍修改密码之前,先介绍一个文件/etc/mysql/debian.cnf.其主要内容如下图: 里面有一个debian-sys-maint用户,这个用户只有Debian或U ...

  8. loc iloc函数的区别

    import pandas as pd data1 = pd.read_excel(r"G:\Python\example1.xlsx") loc 用行列标签,iloc用数字索引. ...

  9. PS图片后期之超简易造光调色方法

    技法是死的,而人是活的,说的简单一点就是我们要学会开拓一下思维,调色的方法并不是只有[可选颜色]而已. 在修片之前,我们先要学会分析,在拍摄这一组照片时我希望有一种夕阳的光穿透晒在脸庞的感觉,而左边的 ...

  10. Java 常用数据结构对象的实现原理 集合类 List Set Map 哪些线程安全 (美团面试题目)

    Java中的集合包括三大类,它们是Set.List和Map, 它们都处于java.util包中,Set.List和Map都是接口,它们有各自的实现类. List.Set都继承自Collection接口 ...