300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > 网络编程--聊天室

网络编程--聊天室

时间:2018-10-25 04:09:43

相关推荐

网络编程--聊天室

网络编程-聊天室

网络编程是指编写运行在多个设备的计算机程序,这些设备通过网络连接起来

主要使用:

包:JavaSE的API包含有类和接口,它们提供低层次的通信细节。

包中提供了两种常见的网络协议的支持:

TCP:TCP是传输控制协议的缩写,它保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称TCP/IP。

UDP:UDP是用户数据报协议的缩写,一个无连接的协议。提供了应用程序之间要发送的数据的数据报。

Socket编程:套接字使用TCP提供两台计算机之间的通信机制。

客户端程序创建一个套接字,并尝试连接服务器的套接字。

当连接建立时,服务器会创建一个 Socket 对象。客户端和服务器现在可以通过对 Socket 对象的写入和读取来进行通信。

因此:

1.服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。

2.服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。

3.服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。

4.Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。

5.在服务器端,accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。

6.连接建立后,通过使用 I/O 流在进行通信,每一个socket都有一个输出流和一个输入流,客户端的输出流连接到服务器端的输入流,而客户端的输入流连接到服务器端的输出流。

/*** 服务端*/import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import .ServerSocket;import .Socket;public class GreetingServer {public static void main(String[] args) throws IOException {//1.创建服务器Server对象和系统要指定的端口号。ServerSocket Server=new ServerSocket(8888);//2.使用成员方法accept(),获取到请求的客户端。Socket so = Server.accept();//3.使用成员方法对象getInputStream获取网络字节输入流对象InputStreamInputStream input = so.getInputStream();//4.使用InputStream对象中方法read()方法读取客户端数据。byte[] bytes=new byte[1024];int len=input.read(bytes);System.out.println(new String(bytes,0,len));//5.使用成员方法对象getOutputStream()获取网络字节输出流对象OutputStreamOutputStream output = so.getOutputStream();//6.使用OutputStream对象中方法write()方法向客户端回送数据。output.write("谢谢收到".getBytes());//7.释放资源(Socket,ServerSocket)so.close();Server.close();}}

/*** 客户端*/import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import .Socket;import java.io.IOException;import .Socket;public class GreetingClient {public static void main(String[] args) throws IOException {//创建一个客户端对象SocketSocket client=new Socket("127.0.0.1",8888);//使用成员方法对象getOutputStream获取网络字节输出流对象OutputStreamOutputStream os = client.getOutputStream();os.write("你好服务器".getBytes());//使用成员方法对象getInputStream获取网络字节输入流对象InputStreamInputStream input = client.getInputStream();//使用InputStream对象中方法read()方法读取数据。byte[] bytes=new byte[1024];int len=input.read(bytes);System.out.println(new String(bytes,0,len));//6.释放资源(Socket)client.close();}}

聊天室功能

聊天室需要一个服务器支持,多个客户端连接服务端,服务端的作用就是接受不同的客户端数据,并转发到其他客户端。

客户端可发发送数据给服务器端,同时客户端也需要接收服务器端返回的数据。客户端的发送数据和接收数据是两个独立的通道,互不影响。

客户端的输出与输入要独立,可以使用多线程来实现。

服务端要为每一个客户端建立一个通道,服务端也使用多线程来实现。

服务端需要创建一个通道的列表,统一管理客户端的通道,为了实现自己发的消息,其他人都可以看到。

在客户端程序里为每一个客户端设置一个名称,约定以@name#开头的格式为私聊,就可以实现私聊的功能。

当程序中发生异常时,线程就停止执行。

总体:

每个客户端在连接到服务器端时,要通过控制台输入自己的名称,然后开始发送消息到服务端,服务端在接收到客户端的连接时,首先输出谁进入了聊天室,然后把客户端发来的消息转发给其他客户端,实现群聊的功能,如果客户端按照约定以@name#开头的格式输入消息,服务端需要解析到客户端要私聊的对象,把消息单独发送给要私聊的客户端。

1.处理IO异常

import java.io.Closeable;/*** 释放资源,由于代码里会处理很多 IO 异常,当程序中发生异常时,线程就停止执行,并且关闭掉对应的资源*/public class Util {public static void closeAll(Closeable... io) {for (Closeable temp : io) {try {if (null != temp) {temp.close();}} catch (Exception e) {e.printStackTrace();}}}}

2.服务器端多线程,维护一个客户端的通道列表,服务端实现既能接受客户端的数据,又能转发给对应的客户端

import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;import .Socket;import java.util.ArrayList;import java.util.List;/*** 实现服务器端的多线程,维护一个客户端的通道列表,服务器端既能接收客户端的数据,又能把数据转发给对应的客户端*/public class ChatChannel implements Runnable{public static List<ChatChannel> all = new ArrayList<ChatChannel>();// 通道列表private DataInputStream dis; // 输入流private DataOutputStream dos;// 输出流private String name;// 客户端名称private boolean isRunning = true;public ChatChannel(Socket client) {try {dis = new DataInputStream(client.getInputStream());dos = new DataOutputStream(client.getOutputStream());this.name = dis.readUTF();System.out.println(this.name + "进入了聊天室");this.send(this.name + ",您好!欢迎您进入聊天室");sendOthers(this.name + "进入了聊天室", true); // 系统消息} catch (IOException e) {e.printStackTrace();Util.closeAll(dis, dos);isRunning = false;}}/*** 读取数据*/private String receive() {String msg = "";try {msg = dis.readUTF();} catch (IOException e) {e.printStackTrace();Util.closeAll(dis);isRunning = false;all.remove(this); // 移除自身}return msg;}/*** 发送数据*/private void send(String msg) {if (msg != null && !"".equals(msg)) {try {dos.writeUTF(msg);dos.flush();} catch (IOException e) {e.printStackTrace();Util.closeAll(dos);isRunning = false;all.remove(this); // 移除自身}}}/*** @param msg 消息内容* @param sysMsg 是否是系统消息*/private void sendOthers(String msg, boolean sysMsg) {// 加入私聊的判断,约定@name#格式为私聊if (msg.startsWith("@") && msg.indexOf("#") > -1) {// 私聊// 获取nameString name = msg.substring(1, msg.indexOf("#"));String content = msg.substring(msg.indexOf("#") + 1);for (ChatChannel other : all) {if (name.equals(other.name)) {other.send(this.name + "悄悄地对您说:" + content);}}} else {for (ChatChannel other : all) {if (other == this) {continue;}if (sysMsg) {other.send("系统信息:" + msg);} else {// 发送其他客户端other.send(this.name + "对所有人说:" + msg);}}}}@Overridepublic void run() {while (isRunning) {sendOthers(receive(), false); // 用户消息}}}

3.创建服务端类Server,使用多线程和通道容器

import java.io.IOException;import .ServerSocket;import .Socket;/*** 创建服务端Server类,使用多线程和通道容器*/public class Server {public static void main(String[] args) throws IOException {ServerSocket server = new ServerSocket(8888);while (true) {Socket client = server.accept();ChatChannel channel = new ChatChannel(client);ChatChannel.all.add(channel);// 统一管理客户端的通道new Thread(channel).start(); // 启动一条通道}}}

4.客户端发送消息线程类Send,设定自己的名字,并发送给服务端

import java.io.BufferedReader;import java.io.DataOutputStream;import java.io.IOException;import java.io.InputStreamReader;import .Socket;/*** 客户端的消息发送线程类 Send,每个客户端要设定自己的名字,同时接收控制台输入的数据并发送给服务端。*/public class Send implements Runnable{// 控制台输入private BufferedReader console;// 输出流private DataOutputStream dos;// 客户端名称private String name;// 控制线程private boolean isRunning = true;public Send(Socket client, String name) {try {console = new BufferedReader(new InputStreamReader(System.in));dos = new DataOutputStream(client.getOutputStream());this.name = name;send(this.name); // 把自己的名字发给服务端} catch (IOException e) {e.printStackTrace();isRunning = false;Util.closeAll(dos, console);}}/*** 从控制台接收数据并发送数据*/public void send(String msg) {try {if (msg != null && !"".equals(msg)) {dos.writeUTF(msg);dos.flush(); // 强制刷新}} catch (IOException e) {e.printStackTrace();isRunning = false;Util.closeAll(dos, console);}}// 从控制台接收数据private String getMsgFromConsole() {try {return console.readLine();} catch (IOException e) {e.printStackTrace();}return "";}@Overridepublic void run() {while (isRunning) {send(getMsgFromConsole());}}}

5.客户端接收消息Receive,用于独立接受服务端返回的数据

mport java.io.DataInputStream;import java.io.IOException;import .Socket;/*** 客户端的消息接收线程类 Receive,用于独立接收服务端返回的数据。*/public class Receive implements Runnable{// 输入流private DataInputStream dis;// 线程标识private boolean isRunning = true;public Receive(Socket client) {try {dis = new DataInputStream(client.getInputStream());} catch (IOException e) {e.printStackTrace();isRunning = false;Util.closeAll(dis);}}/*** 接收数据*/public String receive() {String msg = "";try {msg = dis.readUTF();} catch (IOException e) {e.printStackTrace();isRunning = false;Util.closeAll(dis);}return msg;}@Overridepublic void run() {while (isRunning) {System.out.println(receive());}}}

6.创建客户端类Client,发送和接收数据分布使用独立的多线程

import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import .Socket;/*** 创建客户端类 Client,发送数据和接收数据分布使用独立的多线程处理。*/public class Client {public static void main(String[] args) throws IOException {System.out.println("请输入您的名称:");BufferedReader br = new BufferedReader(new InputStreamReader(System.in));String name = br.readLine();if ("".equals(name)) {return;}Socket client = new Socket("localhost", 8888);new Thread(new Send(client, name)).start(); // 发送一条通道new Thread(new Receive(client)).start(); // 接收一条通道}}

最后,先启动Server,然后可以启动多个客户端Client

客户端启动后,创建名字:

客户端公开发言

客户端私聊

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。