第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. .NET CORE学习笔记系列(2)——依赖注入[6]: .NET Core DI框架[编程体验]

    原文https://www.cnblogs.com/artech/p/net-core-di-06.html 毫不夸张地说,整个ASP.NET Core框架是建立在一个依赖注入框架之上的,它在应用启动 ...

  2. Taro文件上传:Blob Url下载Blob对象本身并通过接口上传到服务器

    最近项目的文件上传遇到一个问题,就是Taro的chooseImage传给回调的是一个Blob对象,一般来说,上传控件都会导出Data Url,而Taro给了一个Blob Url,问题在于,我直接令im ...

  3. day7-基础函数的学习(二)

    过了元旦,加油鸭,冲鸭!!! 闲话不说,开始今日份学习整理. 今日目录,今天的学习内容不是很多! 1.函数名的运用 2.闭包(重要) 3.迭代器(重要) 开始今日份总结 1.函数名的运用 1.1函数名 ...

  4. Django-CRM项目学习(七)-权限组件的设置以及权限组件的应用

    开始今日份整理 1.利用自定制标签,增加展示权限,权限分级设定 1.1 在权限组件中创建自定义标签 使用自定义标签的目的,使各个数据进行分离 1.2 导入自定义标签包 自定义标签复习(自定义标签有三种 ...

  5. 【Windows】+ win10 通过KMS激活

    win10激活到期 通过KMS再次激活(亲测有效):http://www.xitongcheng.com/jiaocheng/win10_article_44435.html

  6. 如何将Bitcoin比特币区块链数据导入关系数据库

    在接触了比特币和区块链后,我一直有一个想法,就是把所有比特币的区块链数据放入到关系数据库(比如SQL Server)中,然后当成一个数据仓库,做做比特币交易数据的各种分析.想法已经很久了,但是一直没有 ...

  7. Android自动化测试手段之Monkey(adb shell monkey)

    一. 什么是Monkey Monkey是Android中的一个命令行工具,可以运行在模拟器里或实际设备中.它向系统发送伪随机的用户事件流(如按键输入.触摸屏输入.手势输入等),实现对正在开发的应用程序 ...

  8. Flask 快速使用 —— (1)

    Flask.Django.Tornado框架 区别 1  Django:重武器,内部包含了非常多组件:ORM.Form.ModelForm.缓存.Session.中间件.信号等... 2   Flas ...

  9. 比sun.misc.Encoder()/Decoder()的base64更高效的mxBase64算法

    package com.mxgraph.online; import java.util.Arrays; /** A very fast and memory efficient class to e ...

  10. windows 比较文件命令--fc

    dos环境下的比较文件命令 win7帮助 D:\test>fc /? 比较两个文件或两个文件集并显示它们之间 的不同 FC [/A] [/C] [/L] [/LBn] [/N] [/OFF[LI ...