第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. ThreadLocal的使用及原理分析

    文章简介 ThreadLocal应该都比较熟悉,这篇文章会基于ThreadLocal的应用以及实现原理做一个全面的分析 内容导航 什么是ThreadLocal ThreadLocal的使用 分析Thr ...

  2. kernel笔记——内核同步与锁

    内核同步 内核同步解决并发带来的问题,多个线程对同一数据进行修改,数据会出现不一致的情况,同步用于保护共享数据等资源. 有两种形式的并发: 同时进行式并发,在不同cpu上执行的进程同时访问共享数据 二 ...

  3. nohup ./startWebLogic.sh >out.log 2>&1 & 解析

    在启动weblogic的时候我们经常看到如下的命令: nohup ./startWebLogic.sh >out.log 2>&1 & 从09年开始用weblogic到现在 ...

  4. Linux 进入 5.0 时代!

    Linux 进入 5.0 时代! 为什么 Linux 4.2 之后的版本不再是 4.21 而是 5.0? 如果你非要一个理由,那就是因为 Linux 4.x 的版本如今用手指与脚趾加在一起都要数不过来 ...

  5. day 12 装饰器

    nonlocal关键字 # 作用:将 L 与 E(E中的名字需要提前定义) 的名字统一​# 应用场景:如果想在被嵌套的函数中修改外部函数变量(名字)的值​# 案例:​def outer():    n ...

  6. Django学习笔记之表单验证

    表单概述 HTML中的表单 单纯从前端的html来说,表单是用来提交数据给服务器的,不管后台的服务器用的是Django还是PHP语言还是其他语言.只要把input标签放在form标签中,然后再添加一个 ...

  7. 用Eclipse中的git提交代码流程

    有更新有提交 Commit到本地,pull,然后再push 提交 Commit到本地 或者直接commit and Push 更新 先对比然后pull或者右键项目直接pull 有冲突时 有冲突的时候优 ...

  8. StatefulSet(一):拓扑状态

    Deployment 实际上并不足以覆盖所有的应用编排问题. 造成这个问题的根本原因,在于 Deployment 对应用做了一个简单化假设. 它认为,一个应用的所有 Pod,是完全一样的.所以,它们互 ...

  9. Object的所有方法

    Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象.它将返回目标对象. const object1 = { a: 1, b: 2, c: 3 }; const ...

  10. Shell命令-文件及内容处理之more、less

    文件及内容处理 - more.less 1. more:分页显示文件内容 more命令的功能说明 more 命令类似 cat,不过会以一页一页的形式显示,更方便使用者逐页阅读,而最基本的指令就是按空白 ...