JavaSocket实现多人聊天室
- 格式:doc
- 大小:166.50 KB
- 文档页数:24
socket编程聊天室基本流程一、引言Socket编程是一种用于网络通信的编程技术。
它允许程序员创建客户端和服务器应用程序,这些应用程序可以在不同的计算机上运行并通过Internet或局域网相互通信。
在本文中,我们将介绍Socket编程聊天室的基本流程。
二、Socket编程概述Socket编程是一种基于TCP/IP协议的网络编程技术。
它使用套接字(socket)来实现网络通信。
套接字是一种抽象概念,它表示一个网络连接点,可以用来发送和接收数据。
在Socket编程中,客户端和服务器之间建立一个连接,然后通过这个连接进行数据传输。
客户端向服务器发送请求,并等待服务器响应。
服务器接收请求并处理它,并将响应发送回客户端。
三、Socket编程聊天室基本流程1. 创建服务器程序首先,我们需要创建一个服务器程序来监听客户端连接请求。
在Python中,可以使用socket模块来创建套接字对象,并使用bind()方法将其绑定到指定的IP地址和端口号上。
2. 创建客户端程序然后,我们需要创建一个客户端程序来连接到服务器。
同样地,在Python中可以使用socket模块来创建套接字对象,并使用connect()方法连接到指定的IP地址和端口号上。
3. 实现消息传输一旦客户端和服务器之间建立了连接,它们就可以开始进行消息传输。
在Socket编程中,可以使用send()方法将数据发送到对方,使用recv()方法从对方接收数据。
4. 实现聊天室功能为了实现聊天室功能,我们需要让多个客户端能够同时连接到服务器,并且能够相互通信。
为此,我们可以使用多线程或异步编程技术来实现。
在多线程模式下,每个客户端连接都会被分配一个独立的线程来处理。
这个线程负责接收客户端发送的消息,并将其转发给其他客户端。
在异步编程模式下,我们可以使用协程或回调函数来处理消息传输。
当有新的消息到达时,就会触发相应的回调函数进行处理。
5. 实现用户管理为了实现用户管理功能,我们需要让每个客户端都能够注册一个唯一的用户名,并且能够查看当前在线的用户列表。
摘要随着互联网的快速发展,网络聊天工具已经作为一种重要的信息交流工具,受到越来越多的网民的青睐.目前,出现了很多非常不错的聊天工具,其中应用比较广泛的有Netmeeting、腾讯QQ、MSN-Messager等等。
该系统开发主要包括一个网络聊天服务器程序和一个网络聊天客户程序两个方面。
前者通过Socket套接字建立服务器,服务器能读取、转发客户端发来信息,并能刷新用户列表。
后者通过与服务器建立连接,来进行客户端与客户端的信息交流。
其中用到了局域网通信机制的原理,通过直接继承Thread类来建立多线程。
开发中利用了计算机网络编程的基本理论知识,如TCP/IP协议、客户端/服务器端模式(Client/Server模式)、网络编程的设计方法等。
在网络编程中对信息的读取、发送,是利用流来实现信息的交换,其中介绍了对实现一个系统的信息流的分析,包含了一些基本的软件工程的方法。
经过分析这些情况,该局域网聊天工具采用Eclipse为基本开发环境和java 语言进行编写,首先可在短时间内建立系统应用原型,然后,对初始原型系统进行不断修正和改进,直到形成可行系统关键词:局域网聊天 socket javaAbstractAlong with the fast development of Internet,the network chating tool has already become one kind of important communication tools and received more and more web cams favor. At present, many extremely good chating tools have appeared . for example,Netmeeting, QQ,MSN—Messager and so on. This system development mainly includes two aspects of the server procedure of the network chat and the customer procedure of the network chat。
多人聊天系统的设计与实现1.系统设计:a.客户端设计:客户端需要有用户界面用于用户输入和显示聊天内容。
用户界面应该支持多人聊天,因此可以设计为一个聊天室的形式,让用户能够选择加入不同的聊天室。
客户端还需要处理消息的发送和接收,并将接收到的消息显示在用户界面上。
b.服务器设计:服务器用于协调客户端之间的通信。
服务器需要根据客户端的请求,将消息发送给指定的客户端。
服务器还需要管理聊天室的创建和销毁,以及处理用户的连接和断开。
2.系统实现:a. 客户端实现:客户端可以使用常见的编程语言(如Python、Java、C++等)进行实现。
客户端需要使用套接字(socket)进行与服务器的通信,并实现发送和接收消息的功能。
客户端还需要设计用户界面以便于用户进行输入和显示聊天内容。
b.服务器实现:服务器也可以使用常见的编程语言进行实现。
服务器需要使用套接字进行与客户端的通信,并维护一个客户端列表用于管理连接的客户端。
服务器需要处理客户端的连接和断开,并根据客户端的请求发送相应的消息给指定的客户端。
3.其他功能的设计与实现:a.聊天记录保存:可以设计一个数据库用于保存聊天记录,以便于用户离线时能够查看历史消息。
b.文件传输:可以设计一个文件传输功能,允许用户发送和接收文件。
c.图片和表情支持:可以设计一个图片和表情支持的功能,允许用户发送和接收图片和表情。
d.用户认证与权限管理:可以设计一个用户认证和权限管理的功能,以确保只有经过认证的用户才能加入聊天室,并按照权限进行相关操作。
e.客户端扩展性:可以设计客户端的扩展性,以便于在未来可以添加更多的功能和插件。
以上是多人聊天系统的设计与实现的一个基本框架和示例。
具体的实现方式和细节可以根据具体的需求来设计和开发。
socket.on的用法Socket.io是一个基于WebSocket协议的网络库,可以帮助开发者轻松地实现即时通信的功能,例如聊天室、多人游戏等。
socket.on是Socket.io中最重要的一个函数之一。
本文将详细介绍socket.on的用法,希望能帮助读者更好地理解Socket.io的使用。
在Socket.io中,socket.on是一个用于监听事件的函数。
它的定义如下:```javascriptsocket.on(eventName, callback);```eventName表示要监听的事件名,callback表示事件被触发时执行的回调函数。
2.1 监听服务器发送的事件在客户端使用Socket.io连接到服务器后,服务器可以向客户端发送事件。
此时,客户端可以通过socket.on来监听这些事件。
例如:```javascript// 监听服务器发送的名为“serverEvent”的事件socket.on('serverEvent', function(data) {console.log('接收到服务器发送的数据:' + data);});```上述代码中,当服务器发送名为“serverEvent”的事件时,客户端会触发回调函数,并将服务器发送的数据作为参数传入。
客户端通过console.log函数将数据输出到控制台。
2.3 监听系统事件上述代码中,当客户端连接到服务器、客户端离开服务器、客户端失去连接时,服务器会触发相应的回调函数,并在控制台中输出相应的提示信息。
除了上述三种常见的事件类型外,Socket.io还支持自定义事件。
例如:三、总结四、注意事项4.1 事件名必须唯一在Socket.io中,事件名是用于标识不同类型事件的字符串。
为了避免事件名的重复,我们应该尽可能在事件名前加上命名空间。
例如:```javascript// 在事件名前加上命名空间socket.on('chat.messageReceived', function(data) {console.log('接收到消息:' + data.message);});```上述代码中,我们在事件名前加上了“chat.”命名空间,以避免与其他事件名冲突。
最新基于websocket与java的多人聊天室实现架构html5+websocket+javaEE7+tomcat8JavaEE7 最新的websocket1.0 APITomcat8开始支持websocket1.0 API【Tomcat implements the Java WebSocket 1.0 API defined by JSR-356】在编写代码之前你要导入javaEE7的jar包以便使用websocket API,将此项目部署到tomcat8里面。
具体代码如下:Java端:ChatAnnotation类;使用的是注解的方式。
package websocket.chat;import java.io.IOException;import java.util.Set;import java.util.concurrent.CopyOnWriteArraySet;import java.util.concurrent.atomic.AtomicInteger;import javax.websocket.OnClose;import javax.websocket.OnError;import javax.websocket.OnMessage;import javax.websocket.OnOpen;import javax.websocket.Session;import javax.websocket.server.ServerEndpoint;import org.apache.juli.logging.Log;import org.apache.juli.logging.LogFactory;import util.HTMLFilter;@ServerEndpoint(value = "/websocket/chat")public class ChatAnnotation {private static final Log log =LogFactory.getLog(ChatAnnotation.class);private static final String GUEST_PREFIX = "Guest";private static final AtomicInteger connectionIds = new AtomicInteger(0);private static final Set<ChatAnnotation> connections =new CopyOnWriteArraySet<>();private final String nickname;private Session session;public ChatAnnotation() {nickname = GUEST_PREFIX + connectionIds.getAndIncrement(); }@OnOpenpublic void start(Session session) {this.session = session;connections.add(this);String message = String.format("* %s %s", nickname, "has joined.");broadcast(message);}@OnClosepublic void end() {connections.remove(this);String message = String.format("* %s %s",nickname, "has disconnected.");broadcast(message);}@OnMessagepublic void incoming(String message) {// Never trust the clientString filteredMessage = String.format("%s: %s",nickname, HTMLFilter.filter(message.toString()));broadcast(filteredMessage);}@OnErrorpublic void onError(Throwable t) throws Throwable {log.error("Chat Error: " + t.toString(), t);}private static void broadcast(String msg) {for (ChatAnnotation client : connections) {try {synchronized (client) {client.session.getBasicRemote().sendText(msg);}} catch (IOException e) {log.debug("Chat Error: Failed to send message to client", e);connections.remove(client);try {client.session.close();} catch (IOException e1) {// Ignore}String message = String.format("* %s %s",client.nickname, "has been disconnected."); broadcast(message);}}}}里面的juli.jar包可以百度一下自行下载。
Java程序课程设计任务书JAVA聊天室的系统的设计与开发1.主要内容:用JAVA实现基于C/S模式的聊天室系统。
聊天室分为服务器端和客户端两部分,服务器端程序主要负责侦听客户端发来的信息,客户端需要登陆到服务器端才可以实现正常的聊天功能。
2.具体要求(包括技术要求等):系统的功能要求:A.服务器端主要功能如下:1.在特定端口上进行侦听,等待客户端连接。
2.用户可以配置服务器端的侦听端口,默认端口为8888。
3.向已经连接到服务器端的用户发送系统消息。
4.统计在线人数。
5.当停止服务时,断开所有的用户连接。
B.客户端的主要功能如下:1.连接到已经开启聊天服务的服务器端。
2.用户可以配置要连接的服务器端的IP地址和端口号。
3.用户可以配置连接后显示的用户名。
4.当服务器端开启的话,用户可以随时登录和注销。
5.用户可以向所有人或某一个人发送消息。
学习并掌握一下技术:Java JavaBean 等熟练使用一下开发工具:Eclipse, JCreator 等实现系统上诉的功能。
3.进度安排:12月28日 ~ 12月29日:课程设计选题,查找参考资料12月30日 ~ 1月1日:完成系统设计1月2日 ~ 1月5日:完成程序代码的编写1月6日:系统测试与完善1月7日:完成课程设计报告,准备答辩4.主要参考文献:[1].张广彬孟红蕊张永宝.Java课程设计(案例精编)[M].清华大学出版社.2007年版摘要在网络越来越发达的今天,人们对网络的依赖越来越多,越来越离不开网络,由此而产生的聊天工具越来越多,例如,国外的ICQ、国内腾讯公司开发的OICQ。
基于Java网络编程的强大功能,本次毕业设计使用Java编写一个聊天系统。
一般来说,聊天工具大多数由客户端程序和服务器程序外加服务器端用于存放客户数据的数据库组成,本系统采用客户机/服务器架构模式通过Java提供的Soket类来连接客户机和服务器并使客户机和服务器之间相互通信,由于聊天是多点对多点的而Java提供的多线程功能用多线程可完成多点对多点的聊天,数据库管理系统用SQL Server2000完成并通过JDBC-ODBC桥访问数据库。
SpringBoot实战之netty-socketio实现简单聊天室(给指定⽤户推送消息)⽹上好多例⼦都是群发的,本⽂实现⼀对⼀的发送,给指定客户端进⾏消息推送1、本⽂使⽤到netty-socketio开源库,以及MySQL,所以⾸先在pom.xml中添加相应的依赖库<dependency><groupId>com.corundumstudio.socketio</groupId><artifactId>netty-socketio</artifactId><version>1.7.11</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency>2、修改application.properties, 添加端⼝及主机数据库连接等相关配置,wss.server.port=8081wss.server.host=localhostspring.datasource.url = jdbc:mysql://127.0.0.1:3306/springlearnername = rootspring.datasource.password = rootspring.datasource.driverClassName = com.mysql.jdbc.Driver# Specify the DBMSspring.jpa.database = MYSQL# Show or not log for each sql queryspring.jpa.show-sql = true# Hibernate ddl auto (create, create-drop, update)spring.jpa.hibernate.ddl-auto = update# Naming strategyspring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy# stripped before adding them to the entity manager)spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect3、修改Application⽂件,添加nettysocket的相关配置信息package com.xiaofangtech.sunt;import org.springframework.beans.factory.annotation.Value;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.Bean;import com.corundumstudio.socketio.AuthorizationListener;import com.corundumstudio.socketio.Configuration;import com.corundumstudio.socketio.HandshakeData;import com.corundumstudio.socketio.SocketIOServer;import com.corundumstudio.socketio.annotation.SpringAnnotationScanner;@SpringBootApplicationpublic class NettySocketSpringApplication {@Value("${wss.server.host}")private String host;@Value("${wss.server.port}")private Integer port;@Beanpublic SocketIOServer socketIOServer(){Configuration config = new Configuration();config.setHostname(host);config.setPort(port);//该处可以⽤来进⾏⾝份验证config.setAuthorizationListener(new AuthorizationListener() {@Overridepublic boolean isAuthorized(HandshakeData data) {//http://localhost:8081?username=test&password=test//例如果使⽤上⾯的链接进⾏connect,可以使⽤如下代码获取⽤户密码信息,本⽂不做⾝份验证// String username = data.getSingleUrlParam("username");// String password = data.getSingleUrlParam("password");return true;}});final SocketIOServer server = new SocketIOServer(config);return server;}@Beanpublic SpringAnnotationScanner springAnnotationScanner(SocketIOServer socketServer) {return new SpringAnnotationScanner(socketServer);}public static void main(String[] args) {SpringApplication.run(NettySocketSpringApplication.class, args);}}4、添加消息结构类MessageInfo.javapackage com.xiaofangtech.sunt.message;public class MessageInfo {//源客户端idprivate String sourceClientId;//⽬标客户端idprivate String targetClientId;//消息类型private String msgType;//消息内容private String msgContent;public String getSourceClientId() {return sourceClientId;}public void setSourceClientId(String sourceClientId) {this.sourceClientId = sourceClientId;}public String getTargetClientId() {return targetClientId;}public void setTargetClientId(String targetClientId) {this.targetClientId = targetClientId;}public String getMsgType() {return msgType;}public void setMsgType(String msgType) {this.msgType = msgType;}public String getMsgContent() {return msgContent;}public void setMsgContent(String msgContent) {this.msgContent = msgContent;}}5、添加客户端信息,⽤来存放客户端的sessionidpackage com.xiaofangtech.sunt.bean;import java.util.Date;import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.Table;import javax.validation.constraints.NotNull;@Entity@Table(name="t_clientinfo")public class ClientInfo {@Id@NotNullprivate String clientid;private Short connected;private Long mostsignbits;private Long leastsignbits;private Date lastconnecteddate;public String getClientid() {return clientid;}public void setClientid(String clientid) {this.clientid = clientid;}public Short getConnected() {return connected;}public void setConnected(Short connected) {this.connected = connected;}public Long getMostsignbits() {return mostsignbits;}public void setMostsignbits(Long mostsignbits) {this.mostsignbits = mostsignbits;}public Long getLeastsignbits() {return leastsignbits;}public void setLeastsignbits(Long leastsignbits) {this.leastsignbits = leastsignbits;}public Date getLastconnecteddate() {return lastconnecteddate;}public void setLastconnecteddate(Date lastconnecteddate) {stconnecteddate = lastconnecteddate;}}6、添加查询数据库接⼝ClientInfoRepository.javapackage com.xiaofangtech.sunt.repository;import org.springframework.data.repository.CrudRepository;import com.xiaofangtech.sunt.bean.ClientInfo;public interface ClientInfoRepository extends CrudRepository<ClientInfo, String>{ ClientInfo findClientByclientid(String clientId);}7、添加消息处理类MessageEventHandler.Javapackage com.xiaofangtech.sunt.message;import java.util.Date;import java.util.UUID;import org.springframework.beans.factory.annotation.Autowired;import ponent;import com.corundumstudio.socketio.AckRequest;import com.corundumstudio.socketio.SocketIOClient;import com.corundumstudio.socketio.SocketIOServer;import com.corundumstudio.socketio.annotation.OnConnect;import com.corundumstudio.socketio.annotation.OnDisconnect;import com.corundumstudio.socketio.annotation.OnEvent;import com.xiaofangtech.sunt.bean.ClientInfo;import com.xiaofangtech.sunt.repository.ClientInfoRepository;@Componentpublic class MessageEventHandler{private final SocketIOServer server;@Autowiredprivate ClientInfoRepository clientInfoRepository;@Autowiredpublic MessageEventHandler(SocketIOServer server){this.server = server;}//添加connect事件,当客户端发起连接时调⽤,本⽂中将clientid与sessionid存⼊数据库//⽅便后⾯发送消息时查找到对应的⽬标client,@OnConnectpublic void onConnect(SocketIOClient client){String clientId = client.getHandshakeData().getSingleUrlParam("clientid");ClientInfo clientInfo = clientInfoRepository.findClientByclientid(clientId);if (clientInfo != null){Date nowTime = new Date(System.currentTimeMillis());clientInfo.setConnected((short)1);clientInfo.setMostsignbits(client.getSessionId().getMostSignificantBits());clientInfo.setLeastsignbits(client.getSessionId().getLeastSignificantBits());clientInfo.setLastconnecteddate(nowTime);clientInfoRepository.save(clientInfo);}}//添加@OnDisconnect事件,客户端断开连接时调⽤,刷新客户端信息@OnDisconnectpublic void onDisconnect(SocketIOClient client){String clientId = client.getHandshakeData().getSingleUrlParam("clientid");ClientInfo clientInfo = clientInfoRepository.findClientByclientid(clientId);if (clientInfo != null){clientInfo.setConnected((short)0);clientInfo.setMostsignbits(null);clientInfo.setLeastsignbits(null);clientInfoRepository.save(clientInfo);}}//消息接收⼊⼝,当接收到消息后,查找发送⽬标客户端,并且向该客户端发送消息,且给⾃⼰发送消息 @OnEvent(value = "messageevent")public void onEvent(SocketIOClient client, AckRequest request, MessageInfo data){String targetClientId = data.getTargetClientId();ClientInfo clientInfo = clientInfoRepository.findClientByclientid(targetClientId);if (clientInfo != null && clientInfo.getConnected() != 0){UUID uuid = new UUID(clientInfo.getMostsignbits(), clientInfo.getLeastsignbits());System.out.println(uuid.toString());MessageInfo sendData = new MessageInfo();sendData.setSourceClientId(data.getSourceClientId());sendData.setTargetClientId(data.getTargetClientId());sendData.setMsgType("chat");sendData.setMsgContent(data.getMsgContent());client.sendEvent("messageevent", sendData);server.getClient(uuid).sendEvent("messageevent", sendData);}}}8、添加ServerRunner.javapackage com.xiaofangtech.sunt.message;import org.springframework.beans.factory.annotation.Autowired;import mandLineRunner;import ponent;import com.corundumstudio.socketio.SocketIOServer;@Componentpublic class ServerRunner implements CommandLineRunner {private final SocketIOServer server;@Autowiredpublic ServerRunner(SocketIOServer server) {this.server = server;}@Overridepublic void run(String... args) throws Exception {server.start();}}9、⼯程结构10、运⾏测试1)添加基础数据,数据库中预置3个客户端testclient1,testclient2,testclient32) 创建客户端⽂件index.html,index2.html,index3.html分别代表testclient1 testclient2 testclient3三个⽤户其中clientid为发送者id, targetclientid为⽬标⽅id,本⽂简单的将发送⽅和接收⽅写死在html⽂件中使⽤以下代码进⾏连接io.connect('http://localhost:8081?clientid='+clientid);index.html ⽂件内容如下<!DOCTYPE html><html><head><meta charset="utf-8" /><title>Demo Chat</title><link href="bootstrap.css" rel="external nofollow" rel="stylesheet"><style>body {padding:20px;}#console {height: 400px;overflow: auto;}.username-msg {color:orange;}.connect-msg {color:green;}.disconnect-msg {color:red;}.send-msg {color:#888}</style><script src="js/socket.io/socket.io.js"></script><script src="js/moment.min.js"></script><script src="/jquery-1.10.1.min.js"></script><script>var clientid = 'testclient1';var targetClientId= 'testclient2';var socket = io.connect('http://localhost:8081?clientid='+clientid);socket.on('connect', function() {output('<span class="connect-msg">Client has connected to the server!</span>');});socket.on('messageevent', function(data) {output('<span class="username-msg">' + data.sourceClientId + ':</span> ' + data.msgContent);});socket.on('disconnect', function() {output('<span class="disconnect-msg">The client has disconnected!</span>');});function sendDisconnect() {socket.disconnect();}function sendMessage() {var message = $('#msg').val();$('#msg').val('');var jsonObject = {sourceClientId: clientid,targetClientId: targetClientId,msgType: 'chat',msgContent: message};socket.emit('messageevent', jsonObject);}function output(message) {var currentTime = "<span class='time'>" + moment().format('HH:mm:ss.SSS') + "</span>";var element = $("<div>" + currentTime + " " + message + "</div>");$('#console').prepend(element);}$(document).keydown(function(e){if(e.keyCode == 13) {$('#send').click();}});</script></head><body><h1>Netty-socketio Demo Chat</h1><br/><div id="console" class="well"></div><form class="well form-inline" onsubmit="return false;"><input id="msg" class="input-xlarge" type="text" placeholder="Type something..."/><button type="button" onClick="sendMessage()" class="btn" id="send">Send</button><button type="button" onClick="sendDisconnect()" class="btn">Disconnect</button></form></body></html>3、本例测试时testclient1 发送消息给 testclient2testclient2 发送消息给 testclient1testclient3发送消息给testclient1运⾏结果如下以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。
使⽤Java和WebSocket实现⽹页聊天室实例代码在没介绍正⽂之前,先给⼤家介绍下websocket的背景和原理:背景在浏览器中通过http仅能实现单向的通信,comet可以⼀定程度上模拟双向通信,但效率较低,并需要服务器有较好的⽀持; flash中的socket 和xmlsocket可以实现真正的双向通信,通过 flex ajax bridge,可以在javascript中使⽤这两项功能. 可以预见,如果websocket⼀旦在浏览器中得到实现,将会替代上⾯两项技术,得到⼴泛的使⽤.⾯对这种状况,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽并达到实时通讯。
在JavaEE7中也实现了WebSocket协议。
原理WebSocket protocol 。
现很多⽹站为了实现即时通讯,所⽤的技术都是轮询(polling)。
轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP request,然后由服务器返回最新的数据给客户端的浏览器。
这种传统的HTTP request 的模式带来很明显的缺点 – 浏览器需要不断的向服务器发出请求,然⽽HTTP request 的header是⾮常长的,⾥⾯包含的有⽤数据可能只是⼀个很⼩的值,这样会占⽤很多的带宽。
⽽⽐较新的技术去做轮询的效果是Comet – ⽤了AJAX。
但这种技术虽然可达到全双⼯通信,但依然需要发出请求。
在 WebSocket API,浏览器和服务器只需要做⼀个握⼿的动作,然后,浏览器和服务器之间就形成了⼀条快速通道。
两者之间就直接可以数据互相传送。
在此WebSocket 协议中,为我们实现即时服务带来了两⼤好处:1. Header互相沟通的Header是很⼩的-⼤概只有 2 Bytes2. Server Push服务器的推送,服务器不再被动的接收到浏览器的request之后才返回数据,⽽是在有新数据时就主动推送给浏览器。
Swoole案例:基于WebSocket的多人在线聊天室1. 案例背景随着互联网的发展和智能手机的普及,实时通信变得越来越重要。
传统的HTTP协议在实现实时通信时存在一些限制,而WebSocket协议则可以提供双向通信的能力,使得实时通信更加高效和稳定。
Swoole是一个基于PHP语言开发的协程网络通信引擎,提供了丰富的网络编程组件和工具,可以方便地实现高性能的网络应用。
在本案例中,我们将使用Swoole来构建一个基于WebSocket的多人在线聊天室,实现实时的多人聊天功能。
2. 案例过程2.1 环境准备在开始之前,需要确保已经安装了PHP和Swoole扩展。
可以通过以下命令来安装Swoole扩展:$ pecl install swoole2.2 服务器端代码首先,我们需要创建一个服务器端的PHP脚本,用于接收和处理客户端的连接和消息。
在这个案例中,我们使用Swoole的WebSocket服务器类来实现服务器端的功能。
<?php// 创建WebSocket服务器$server = new Swoole\WebSocket\Server("0.0.0.0", 9501);// 监听WebSocket连接事件$server->on('open', function (Swoole\WebSocket\Server $server, $request) { echo "New connection: {$request->fd}\n";});// 监听WebSocket消息事件$server->on('message', function (Swoole\WebSocket\Server $server, $frame) { echo "Received message: {$frame->data}\n";// 广播消息给所有客户端foreach ($server->connections as $fd) {$server->push($fd, $frame->data);}});// 监听WebSocket关闭事件$server->on('close', function ($server, $fd) {echo "Connection closed: {$fd}\n";});// 启动WebSocket服务器$server->start();上述代码中,我们创建了一个WebSocket服务器,并监听了open、message和close三个事件。
JAVA课程设计报告聊天室一、课程目标知识目标:1. 学生能理解网络编程的基本概念,掌握JAVA Socket编程的基础知识。
2. 学生能运用面向对象编程思想,设计并实现聊天室客户端与服务器的数据传输功能。
3. 学生了解并掌握多线程技术在网络编程中的应用。
技能目标:1. 学生能运用所学知识,独立编写并调试简单的聊天室程序。
2. 学生具备分析问题、解决问题的能力,能针对聊天室程序进行优化和改进。
3. 学生能在团队协作中发挥自己的作用,与他人共同完成一个完整的网络编程项目。
情感态度价值观目标:1. 学生培养对计算机编程的兴趣,增强学习JAVA的自信心。
2. 学生认识到团队合作的重要性,培养良好的团队协作精神。
3. 学生通过编程实践,体验创新与创造的乐趣,培养积极向上的学习态度。
本课程针对高年级学生,结合课本内容,注重理论与实践相结合,以提高学生的实际编程能力为主要目标。
课程要求学生在掌握基本知识的基础上,能够独立完成实际项目,培养其分析问题、解决问题的能力。
同时,课程强调团队协作,使学生学会与他人共同进步,共同成长。
通过本课程的学习,使学生达到知识、技能和情感态度价值观的全面提升。
二、教学内容1. 网络编程基础理论:介绍网络编程的基本概念,包括IP地址、端口号、协议等,使学生理解网络通信的基本原理。
- 教材章节:第三章 网络编程基础2. JAVA Socket编程:讲解Socket编程的原理,指导学生掌握客户端与服务器之间的数据传输方法。
- 教材章节:第四章 Socket编程3. 面向对象编程:运用面向对象编程思想,设计聊天室程序,包括类的定义、封装、继承与多态。
- 教材章节:第二章 面向对象编程基础4. 多线程技术:介绍多线程编程的概念,分析在聊天室程序中如何实现多用户并发通信。
- 教材章节:第五章 多线程编程5. 聊天室程序设计与实现:指导学生完成聊天室客户端与服务器的编写,实现基本的功能需求。
JAVA程序设计课程设计报告课题: 基于Socket的聊天程序姓名:骑蚂蚁去流浪学号:0213同组姓名:专业班级:计科0912班指导教师:刘国清设计时刻:2012年上学期第01周评阅意见:评定成绩:指导老师签名:年月日目录一、前言 (2)二、课题概述 (2)(一)课题概述 (3)(二)相关技术 (3)三、系统设计 (3)(一)需求分析 (4)(二)系统功能 (5)(三)系统架构 (6)(四)模块设计 (7)四、详细设计与实现 (8)(一)服务端设计 (8)(二)客户端设计 (9)(三)辅助类设计 (10)五、系统运行结果 (11)六、结论与总结 (13)(一)课程设计结论 (13)(二)课程设计总结与体会 (14)七、附录 (15)一、前言Java课程设计是运算机科学与技术专业学生必做的集中实践性环节之一,是学习完《Java程序设计》课程后进行的一次全面的综合练习。
其目的在于通过课程设计,能够取得较系统的技术训练,从而巩固和加深对Java 编程的基础理论知识的理解,提高综合运用所学理论解决实际问题的能力,成为具有扎实的运算机理论基础和较强的独立动手能力的复合型、应用型人材。
二、课题概述、课题概述现今社会,网络技术愈来愈进展,能够说,二十一世纪就是网络的世纪。
网络迅猛进展,势不可挡。
为了实现资源共享,各式各样的网站进展迅速,各类各样的聊天工具不断更新。
本次课程设计选择一个以JAVA语言实现一个基于Socket的网络聊天室程序。
本系统提供一个网络交互平台,各用户之间能够实时方便的传递信息,能够在聊天室里实现群聊。
本系统主如果利用JAVA语言基于Socket通信机制制作的一个聊天室,采用的是客户/服务器。
二层的C/S结构是指以单一的服务器和局域网为核心,能通过客户端与用户进行直接对话。
为利用户能直观地进行操作,一般要利用图形用户接口(GUI),操作简单、易学易用。
在变更用户接口时,只需改写显示控制和数据检查程序,而不影响其他。
java websocket案例摘要:1.Java WebSocket 简介2.WebSocket 案例一:聊天室3.WebSocket 案例二:在线投票4.WebSocket 案例三:实时股票信息5.总结正文:1.Java WebSocket 简介Java WebSocket 是一种在单个TCP 连接上进行全双工通信的协议。
相较于HTTP,WebSocket 提供了更快的数据传输速度和更低的延迟,使得实时应用和交互成为可能。
在Java 中,我们可以通过使用WebSocket API 和相关的库来实现WebSocket 应用。
2.WebSocket 案例一:聊天室聊天室是一个经典的实时通信应用。
在这个案例中,我们可以使用Java WebSocket 实现一个简单的聊天室,让用户能够实时地发送和接收消息。
通过WebSocket,我们可以实现客户端与服务器之间的双向通信,让用户能够实时地看到其他人发送的消息。
3.WebSocket 案例二:在线投票在线投票是一个实时的数据收集和处理应用。
使用Java WebSocket,我们可以实现一个实时的在线投票系统。
在这个系统中,用户可以实时地投票并查看投票结果。
通过WebSocket,我们可以实时地更新投票数据,让用户能够看到实时的投票结果。
4.WebSocket 案例三:实时股票信息实时股票信息是一个需要快速响应的应用。
使用Java WebSocket,我们可以实现一个实时的股票信息展示系统。
在这个系统中,用户可以实时地查看股票的涨跌情况。
通过WebSocket,我们可以实时地更新股票数据,让用户能够看到实时的股票信息。
5.总结Java WebSocket 为实时应用和交互提供了强大的支持。
通过使用WebSocket,我们可以实现聊天室、在线投票和实时股票信息等应用,为用户提供更加丰富和实时的体验。
设计聊天室实验报告一、实验目的本实验的目的是设计一个基于网络的聊天室,实现多用户之间的实时聊天功能。
通过这个实验,我们可以更好地理解计算机网络通信的原理和网络编程的基本知识,同时提高我们的编程能力和团队协作能力。
二、实验内容1.搭建网络环境首先,我们需要搭建一个网络环境,使得多个用户可以通过网络进行通信。
我们选择使用Socket编程,通过TCP/IP协议进行通信。
我们使用Python语言进行编程,通过socket模块中的函数来创建网络连接。
2.实现用户注册和登录功能在聊天室中,每个用户都需要有自己的账户并进行登录操作。
在实验中,我们使用MySQL数据库来存储用户的账户信息。
用户可以通过注册功能来创建自己的账户,并使用登录功能进行登录。
在用户登录成功后,系统将会为其分配一个唯一标识符,并将其保存在服务端。
3.实现聊天功能在登录成功后,用户可以进入聊天室进行聊天操作。
用户可以发送消息给其他用户,并且可以实时接收其他用户发送的消息。
在实现聊天功能时,我们使用多线程的方式,使得每个用户可以同时进行收发消息的操作。
同时,为了保证消息的有序性,我们使用队列来存储用户发送的消息,并使用互斥锁来保护队列的访问。
4.实现用户列表功能为了方便用户之间的选择和通信,我们实现了用户列表功能。
用户可以查看当前在线的用户,并选择要发送消息的目标用户。
在用户列表中,我们显示用户的昵称和状态信息。
三、实验结果通过本次实验,我们成功实现了基于网络的聊天室,并且完成了所有的实验内容。
实际测试中,我们模拟多个用户在不同的终端进行登录和聊天操作,并得到了预期的结果。
用户可以通过注册功能来创建自己的账户,并通过登录功能进行登录。
登录成功后,用户可以进入聊天室进行聊天操作,并可以看到其他用户发送的消息。
同时,用户也可以选择特定的用户进行私聊。
四、实验总结通过本次实验,我们对计算机网络通信的原理和网络编程有了更深入的了解。
我们学会了如何使用Socket编程进行网络连接,并实现了用户注册、登录、聊天和用户列表等功能。
只要给我一点光,我会发出万象光芒。
本次教程是一个自由聊天室,用到Socket 通讯和线程的技术来做一个简单的自由聊天室。
首先要有一定的知识储备。
一、知识储备1、 Socket 通讯的原理。
根据上图的表示,可以将两台计算机Socket 通讯的想象成是两台电话通讯的过程。
(1) 首先服务端建立起ServerSocket 连接对象,绑定到一下特定的端口,而我们可以将这个端口(必需是空闲的)想象成电话号码。
(2) 执行ServerSocket 对象的accept 方法,而这个方法的作用是用来等待连接。
等待什么呢?是等待客户端连接上来,才执行下面的程序相当于等别人打电话进来。
如果没有客户端的请求上来的话,将一直阻塞在这个方法里,一直等下去,就好像在等别人的电话。
(3) 创建客户端的Socket 对象,主动发起连接,建立网络连接。
相当于主动向某一个人打电话。
里面的host 和port 是指要连接上的服务器端的ip 和端口号。
(4) 一旦连接成功,双方即平等,双方都有一个Socket 的对象。
(5) 双方都建立输入输出流来进行通讯,就好像我们连通了电话之后,开始进行说话。
OutputStream 相当于话筒,InputStream 相当于听筒,于是他们就是这样一边是说,一边是听进行通讯。
(6) 当通讯结束之后,当然要关闭Socket 对象,即讲完电话之后要挂机一样。
2、多线程进程:可以简单认为,一个程序称为一个进程,而一个进程要执行任务,就必须在进程中启动线程,由进程中的线程来执行。
线程:一个线程,指程序运行后执行的一个任务流程普通Java 应有程序一运行,就会执行main 方法里的代码,一行一行执行下去,这个一行一行执行的流程,称为一个线程。
话筒 听筒 话筒听筒而一个进程一启动就拥有一个默认线程,来执行进程默认要执行的任务,也就是执行main的线程。
其实简单点认为,是一个继承Thead的类,这些类与一般类不同之处在于它们是可以并发处理的。
Python基于Socket实现简易多⼈聊天室的⽰例代码前⾔套接字(Sockets)是双向通信信道的端点。
套接字可以在⼀个进程内,在同⼀机器上的进程之间,或者在不同主机的进程之间进⾏通信,主机可以是任何⼀台有连接互联⽹的机器。
套接字可以通过多种不同的通道类型实现:Unix域套接字,TCP,UDP等。
套接字库提供了处理公共传输的特定类,以及⼀个⽤于处理其余部分的通⽤接⼝。
socket模块:要创建套接字,必须使⽤套接字模块中的socket.socket()函数,该函数具有⼀般语法s = socket.socket (socket_family, socket_type, protocol = 0)参数描述socket_family它的值可以是:AF_UNIX或AF_INET,如前所述。
socket_type它的值可以是:SOCK_STREAM或SOCK_DGRAM。
protocol这通常被省略,默认为0。
常⽤⽅法:序⽅法描述号1s.bind()此⽅法将地址(主机名,端⼝号对)绑定到套接字。
2s.recvfrom()此⽅法接收UDP消息,返回值是⼀对(字节,地址),其中字节是代表接收到的数据的字节对象,⽽地址是发送数据的套接字的地址3s.sendto()此⽅法发送UDP消息,将数据发送到套接字。
该套接字不应连接到远程套接字,因为⽬标套接字是由address指定的4s.close()此⽅法关闭套接字,套接字对象上所有以后的操作都将失败。
远端将不再接收任何数据(在清除排队的数据之后)。
套接字在被垃圾回收时会⾃动关闭5socket.gethostname()返回主机名,返回⼀个字符串,其中包含当前正在执⾏Python解释器的计算机的主机名。
⽰例1服务器端#sever.pyimport sockets = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)host = socket.gethostname()port = 8088s.bind((host,port))try:while True:receive_data,addr = s.recvfrom(1024)print("来⾃服务器" + str(addr) + "的消息:")print(receive_data.decode('utf-8'))msg = input('please input send to msg:')s.sendto(msg.encode('utf-8'),addr)except:s.close()客户端#client.pyimport sockets = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)try:while True:host = socket.gethostname()port = 8088send_data = input('please input msg:')s.sendto(send_data.encode('utf-8'),(host,port))msg,addr = s.recvfrom(1024)print("来⾃服务器" + str(addr) + "的消息:")print(msg.decode('utf-8'))except:s.close()服务端⽰例客户端⽰例简易的UDP聊天实现了,下⾯我们来优化⼀下⽰例。
利用JAVA实现简单聊天室1.设计思路Java是一种简单的,面向对象的,分布式的,解释的,键壮的,安全的,结构中立的,可移植的,性能很优异的,多线程的,动态的语言。
而且,Java 很小,整个解释器只需215K的RAM。
因此运用JAVA程序编写聊天室,实现简单聊天功能。
程序实现了聊天室的基本功能,其中有:(1)启动服务器:实现网络的连接,为注册进入聊天室做准备。
(2)注册登陆界面:填写基本信息如姓名等,可以供多人进入实现多人聊天功能。
(3)发送信息:为用户发送信息提供平台。
(4)离开界面:使用户退出聊天室。
(5)关闭服务器:断开与网络的连接,彻底退出聊天室。
2.设计方法在设计简单聊天室时,需要编写5个Java源文件:Server.java、Objecting.java、LogIn.java、ClientUser.java、Client.java。
3 程序功能图及程序相关说明(1)主功能框图(2) 聊天室基本功能表4.程序代码是说明程序中引入的包:package Chat; import .*;import java.awt.*;import java.awt.event.*;import javax.swing.*;import java.util.*;import java.io.*;(1)服务器端代码中用户自定义类:类名:Server作用:服务器启动继承的接口名:ActionListenerpublic class Server implements ActionListener{定义的对象:count //记录点机关闭按钮次数2次关闭soconly //只有SOCKET,用于群发sockets//所有客户的SOCKETsocket_thread //Socket所在的线乘,用于退出;frame // 定义主窗体panel //定义面板start,stop //启动和停止按钮主要成员方法:public void center //定义小程序查看器的位置public void actionPerformed //定义处理异常机制定义子类:serverRun,Details继承的父类名:Threadclass serverRun extends Thread //启线乘用于接收连入的Socket class Details extends Thread //具体处理消息的线乘,只管发送消息创建一个ServerSocket 对象,用于接受指定端口客户端的信息ServerSocket server = new ServerSocket("1234");接受请求时候,通过accept()方法,得到一个socket对象。
JavaSocket实现聊天室附1500⾏源代码⽬录项⽬需求分析基础分析项⽬部分代码摘要Dao的链表存储实现ServerListenServerReceive再看⼀下客户端的ClientReceive项⽬问题选择框中出现的不是⽤户名服务端点击消息发送按钮没有反应不能显⽰在线⼈数服务端退出时没有消息Java养成计划(打卡第31,2天)内容管理:Sockect聊天室的实现Java界⾯使⽤了各种组件,对于这部分不了解的不⽤担⼼,⽬前掌握⼀个⼤概就OK项⽬需求分析需要完成⼀个简单聊天⼯具的界⾯及功能,实现服务器中转下的多客户端之间的通信,系统完成的功能有程序启动后能看到当前有那些机器上线,可弹出对话聊天框,可以在其中编辑要发送的聊天信息,并进⾏发送⼀旦某个⽹内的机器上线了,可即时通知,并能更新⽤户界⾯的⽤户列表双击某个列表项时,可弹出对话聊天框,可以在其中编辑要发送的信息并发送聊天界⾯⼈性化,下⾯时发送框,上⾯有已有聊天记录,并借助滚动条看到当次所有聊天记录当有⼈向本机器发送消息时,可显⽰⽤户接收到的信息,并且显⽰是谁所发,同时进⾏信息的回复基础分析⾸先这是⼀个聊天⼯具,使⽤的是C/S结构,要模拟就要使⽤net的Scocket和ServerSocket模拟客户端和服务端这⾥综合运⽤了多种知识,已经不再是简单的java SE知识,其中界⾯编程占据主要代码,这⾥可以贴⼏张图看看效果,这是我肝了2天才肝完的,这⾥已经可以实现多态设备的连接分为3个包Sever包主要是服务器的相关代码,主要是实现与⽤户的交互Dao包是模拟的数据库包,存储所有的⽤户信息,实现增删改的操作Client是客户代码包,只要在电脑上运⾏这⾥的代码,就可以出现客户端界⾯,约定好ip和端⼝号就可以通信了。
这⾥就真正实现了客户端型软件,只是软件功能简单,可以使⽤web编程实现另外⼀种架构可以来看⼀下界⾯再来看⼀下客户端和服务端的交流项⽬部分代码摘要Dao的链表存储实现package Dao;/*** 演⽰程序为了简化就不⽤数据库存储,使⽤单链表完成数据库各项功能* 这⾥⼀定要写测试代码检查各项功能是否可⽤* 最开开始我测试了add,del,find功能,却没有测试getCount功能,结果存在问题,后⾯突然放开测试才发现错误 */public class UserLinkList {private Node head;private int count;public boolean addUser(Node client){if(head == null){//头节点也存储数据head = client;count++;return true;}else {Node p = head;for(;p.next != null;p = p.next);{p.next = client;count++;return true;}}}public int getCount() {return count;}public Node findUser(String name){Node p = head;while(p != null )//p.next != null没有包含最后⼀个结点{if(ername.equals(name)){return p;}p = p.next;}return null;}public Node findUser(int index){int pos = 0;Node p = head;while(p != null&& pos < index){p = p.next;pos++;}if(p != null&& pos == index){return p;}return null;}public boolean delUser(Node client){//删除后长度也要减少Node p = head;if(ername.equals(ername)){//删除头结点head = head.next;count--;return true;}while(p != null){//忘记循环了if(ername.equals(ername)){p.next = p.next.next;count--;return true;}p = p.next;}return false;}/*** 这⾥可以设置⼀个显⽰的⽅法,供检查使⽤*/public void display() {Node p = head;int pos = 1;while(p != null){System.out.println("第"+pos + "个⽤户"+ername);p = p.next;pos++;}}}/*public static void main(String[] args) {//经过测试发现没有问题,可以正常使⽤ Node client1 = new Node();ername = "张三";Node client2 = new Node();ername = "李四";Node client3 = new Node();ername = "王五";//其他的就不测试了,反正该项就可以测试了UserLinkList userLinkList = new UserLinkList();//⾃动初始化userLinkList.addUser(client1);userLinkList.addUser(client2);userLinkList.addUser(client3);// userLinkList.display();Node node = userLinkList.findUser(0);userLinkList.delUser(node);userLinkList.display();System.out.println(userLinkList.getCount());}*/现在编写这段代码应当是⾮常简单的,注意⼀定要测试ServerListen简单看⼀下这个监听线程,可以监听⽤户是否上线package Server;/*** @author OMEY-PC*本程序的作⽤是实现服务器侦听的线程化,其中run⽅法通过client = new Node();创建⼀个客户端对象,通过client.socket = server.accept来设定接⼝,通过client.input *output来建⽴输⼊输出流*/import java.io.*;import .*;import Dao.*; //连接数据import javax.swing.*;public class ServerListen extends Thread{ServerSocket server;JComboBox combobox;JTextArea textarea;JTextField textfield;UserLinkList userLinkList;Node client;ServerReceive recvThread;public boolean isStop;/*** 聊天服务端的⽤户上下线侦听类*/public ServerListen(ServerSocket server,JComboBox combobox,JTextArea textarea,JTextField textField,UserLinkList userLinkList) {this.server = server;bobox = combobox;this.textarea = textarea;this.textfield = textField;erLinkList = userLinkList;isStop = false;}@Overridepublic void run() {while(!isStop && !server.isClosed())//没有停⽌服务{try {client = new Node();client.socket = server.accept();//⽤来指代所连接的客户端client.output = new ObjectOutputStream(client.socket.getOutputStream());client.output.flush();client.input = new ObjectInputStream(client.socket.getInputStream());ername = (String)client.input.readObject();//显⽰提⽰信息combobox.addItem(ername);//改成⽤户名userLinkList.addUser(client);textarea.append("⽤户" + ername+"上线"+"\n");textfield.setText("在线⽤户"+ userLinkList.getCount()+"⼈\n");recvThread = new ServerReceive(textarea,textfield,combobox,client,userLinkList);recvThread.start();//启动线程}catch (Exception e) {e.printStackTrace();}}}}ServerReceive该线程实现服务器与⽤户之间的信息交互package Server;/*** @author OMEY-PC*服务器收发消息的类*/import .ServerSocket;import javax.swing.*;import Dao.*;public class ServerReceive extends Thread{JTextArea textarea;//消息展⽰域JTextField textfield;//⽂本输⼊域JComboBox combobox; //复选框Node client;//⽤户UserLinkList userLinkList;public boolean isStop;public ServerReceive(JTextArea textarea, JTextField textfield, JComboBox combobox, Node client,UserLinkList userLinkList) {this.textarea = textarea;this.textfield = textfield;bobox = combobox;this.client = client;erLinkList = userLinkList;isStop = false;}@Overridepublic void run(){//向所有⼈发送⽤户的列表sendUserList();while(!isStop && !client.socket.isClosed()){try {//类型,对谁,状况,⾏为,信息String type = (String)client.input.readObject();if(type.equalsIgnoreCase("聊天信息")){String toSomebody =(String)client.input.readObject();//从客户端接收信息String status = (String)client.input.readObject();String action = (String)client.input.readObject();String message = (String)client.input.readObject();String msg = ername+" "+ action + "对"+ toSomebody +" 说 " + message + "\n";//接收的消息 if(status.equalsIgnoreCase("悄悄话")){msg = "[悄悄话]" + msg; //若为悄悄话,就在前⾯加上标识}textarea.append(msg);if(toSomebody.equalsIgnoreCase("所有⼈")){sendToAll(msg);//这⾥是接受的⽤户消息,和之前的向所有⼈发消息不⼀样}else {//向⽤户发消息try {client.output.writeObject("聊天信息");client.output.flush();//刷新流client.output.writeObject(msg);client.output.flush();}catch (Exception e) {e.printStackTrace();}Node node = userLinkList.findUser(toSomebody);if(node != null){node.output.writeObject("聊天信息");node.output.flush();node.output.writeObject(msg);//向选定信息发送信息node.output.flush();//刷新输出流缓冲区中的信息}}}else if(type.equalsIgnoreCase("⽤户下线")){Node node = userLinkList.findUser(ername);userLinkList.delUser(node);String msg = "⽤户"+ ername +"下线\n";int count = userLinkList.getCount();combobox.removeAllItems();combobox.addItem("所有⼈");int i = 0;while(i < count){node = userLinkList.findUser(i);if(node == null){i++;continue;}combobox.addItem(ername);i++;}combobox.setSelectedIndex(0);//选择第⼀个,所有⼈textarea.append(msg);textfield.setText("在线⽤户"+ userLinkList.getCount() +"⼈\n");sendToAll(msg);sendUserList();//重新发送⽤户列表break;}}catch (Exception e) {e.printStackTrace();}}}/*** 向所有⼈发送消息*/public void sendToAll(String msg){int count = userLinkList.getCount();int i = 0;while(i < count){//给⽤户列表中的每⼀个⼈都发送消息Node node = userLinkList.findUser(i);if(node == null){i++;continue;}try {//输出流node.output.writeObject("聊天信息");node.output.flush();node.output.writeObject(msg);//聊天消息写⼊输出流(to client)node.output.flush();}catch (Exception e) {e.printStackTrace();}i++;}}/*** 向所有⼈发送⽤户列表*/public void sendUserList() {String userList = "";int count = userLinkList.getCount();int i = 0;while(i < count){Node node = userLinkList.findUser(i);if(node == null){i++;continue;}userList += ername;userList += "\n";i++;}i = 0; //给每个⼈发送消息while(i < count){Node node = userLinkList.findUser(i);if(node == null){i++;continue;}try {node.output.writeObject("⽤户列表");node.output.flush();node.output.writeObject(userList);node.output.flush();}catch (Exception e) {e.printStackTrace();}}i++;}}/*** 本程序可以实现通过线程向所有⼈发送消息,⽤户列表,以及向选定的⼈发送聊天消息等,主要是是实现服务端收发消息的线程化,其中sendUserList()发送列表, * client.input.redObject()获取客户端发送到服务端的消息,通sendToAll(),将发送到发送到所有⼈的信息发送到各个客户端*/再看⼀下客户端的ClientReceive该线程是实现客户端与系统之间的信息交互,注解丰富package Client;import java.io.*;import .*;import javax.swing.*;public class ClientReceive extends Thread{private JComboBox combobox;private JTextArea textarea;Socket socket;ObjectOutputStream output;ObjectInputStream input;JTextField showStatus;public ClientReceive(JComboBox combobox, JTextArea textarea, Socket socket, ObjectOutputStream output,ObjectInputStream input, JTextField showStatus) {bobox = combobox;this.textarea = textarea;this.socket = socket;this.output = output;this.input = input;this.showStatus = showStatus;}@Overridepublic void run() {//从服务端获得消息while(!socket.isClosed()){try {String type = (String)input.readObject();//获得流,read读取信息if(type.equalsIgnoreCase("系统信息")){String sysmsg = (String)input.readObject();textarea.append("系统信息" + sysmsg);}else if(type.equalsIgnoreCase("服务关闭")){output.close();input.close();socket.close();textarea.append("服务器已经关闭!\n");break;}else if(type.equalsIgnoreCase("聊天信息")){String message = (String)input.readObject();textarea.append(message);}else if(type.equalsIgnoreCase("⽤户列表")){String userlist = (String)input.readObject();String[] usernames = userlist.split("\n"); //⽤换⾏符分隔combobox.removeAll();//先移出去int i = 0;combobox.addItem("所有⼈");while(i < usernames.length){combobox.addItem(usernames[i]);i++;}combobox.setSelectedIndex(0);showStatus.setText("在线⽤户"+ usernames.length +" ⼈");}}catch (Exception e) {e.printStackTrace();}}}}其余的界⾯的部分就不放出来了,代码太长,每个都有400多⾏,如果有兴趣,就到我的gitee上去浏览,后⾯会放上地址项⽬问题选择框中出现的不是⽤户名查找相应模块发现是因为addItem中添加的时结点,⽽不是结点中的username,修改后正常服务端点击消息发送按钮没有反应查找监听器部分,发现监听器监听该部分代码写错,将button⼜写成sysMessage不能显⽰在线⼈数查找侦听线程,启动客户端发现抛出异常Cannot invoke “javax.swing.JTextField.setText(String)” because “this.textfield” is nulltextfield为空,查找问题源头;发现在构造⽅法中:the assignmen to variable has no effect;这是因为单词拼写错误,编译器并没有报错服务端退出时没有消息系统报错Cannot read field “input” because “node” is null意识到问题出在链表上,系统要求从0开始,⽽链表中的序号是从1开始的,修该链表中的findUser中的pos为0就解决写这个程序写了两天,直接废了~~到此这篇关于Java Socket实现聊天室附1500⾏源代码的⽂章就介绍到这了,更多相关Java Socket内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!。
Java Socket实现多人聊天室---swing做UI标签:socket聊天javaexception服务器string2011-08-31 15:0620679人阅读评论(25)收藏举报分类:java(21)版权声明:本文为博主原创文章,未经博主允许不得转载。
今天翻硬盘的workspace发现一个Java Socket实现多人聊天室的源码,不记得是什么时候的事情了,貌似不是我写的。
但写得还不错,至少算个有模有样的聊天室工具。
我简单的修改了一下,拿出来跟大家分享一下,仅供参考。
界面是用swing写的,还不懒,简约大方。
有图有真相:正如上图所示,这个程序分为服务器端和客户端,说白了就是两个main class,用eclipse 直接运行之。
聊天室的设计思想是:在局域网下,利用socket进行连接通信,当服务器端启动的时候,利用Thread线程不停的等待客户端的链接;当有客户端开启连接的时候,服务器端通过IO流反馈“上线用户”信息给客户端,客户端也使用线程不停的接收服务器的信息,从而实现多人在线聊天功能。
程序中有三个类,分别Server.java(服务器端)、Client(客户端)、User.java(javabean)。
代码如下:Server.java(服务器端):[html]view plaincopy1.import java.awt.BorderLayout;2.import java.awt.Color;3.import java.awt.GridLayout;4.import java.awt.Toolkit;5.import java.awt.event.ActionEvent;6.import java.awt.event.ActionListener;7.import java.awt.event.WindowAdapter;8.import java.awt.event.WindowEvent;9.import java.io.BufferedReader;10.import java.io.IOException;11.import java.io.InputStreamReader;12.import java.io.PrintWriter;13.import .BindException;14.import .ServerSocket;15.import .Socket;16.import java.util.ArrayList;17.import java.util.StringTokenizer;18.19.import javax.swing.DefaultListModel;20.import javax.swing.JButton;21.import javax.swing.JFrame;22.import javax.swing.JLabel;23.import javax.swing.JList;24.import javax.swing.JOptionPane;25.import javax.swing.JPanel;26.import javax.swing.JScrollPane;27.import javax.swing.JSplitPane;28.import javax.swing.JTextArea;29.import javax.swing.JTextField;30.import javax.swing.border.TitledBorder;31.32.public class Server{33.34.private JFrame frame;35.private JTextArea contentArea;36.private JTextField txt_message;37.private JTextField txt_max;38.private JTextField txt_port;39.private JButton btn_start;40.private JButton btn_stop;41.private JButton btn_send;42.private JPanel northPanel;43.private JPanel southPanel;44.private JScrollPane rightPanel;45.private JScrollPane leftPanel;46.private JSplitPane centerSplit;47.private JList userList;48.private DefaultListModel listModel;49.50.private ServerSocket serverSocket;51.private ServerThread serverThread;52.private ArrayList<ClientThread>clients;53.54.private boolean isStart=false;55.56.//主方法,程序执行入口57.public static void main(String[]args){58.new Server();59.}60.61.//执行消息发送62.public void send(){63.if(!isStart){64.JOptionPane.showMessageDialog(frame,"服务器还未启动,不能发送消息!","错误",65.JOptionPane.ERROR_MESSAGE);66.return;67.}68.if(clients.size()==0){69.JOptionPane.showMessageDialog(frame,"没有用户在线,不能发送消息!","错误",70.JOptionPane.ERROR_MESSAGE);71.return;72.}73.String message=txt_message.getText().trim();74.if(message==null||message.equals("")){75.JOptionPane.showMessageDialog(frame,"消息不能为空!","错误",76.JOptionPane.ERROR_MESSAGE);77.return;78.}79.sendServerMessage(message);//群发服务器消息80.contentArea.append("服务器说:"+txt_message.getText()+"\r\n");81.txt_message.setText(null);82.}83.84.//构造放法85.public Server(){86.frame=new JFrame("服务器");87.//更改JFrame的图标:88.//frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Client.class.getResource("qq.png")));89.frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Server.class.getResource("qq.png")));90.contentArea=new JTextArea();91.contentArea.setEditable(false);92.contentArea.setForeground(Color.blue);93.txt_message=new JTextField();94.txt_max=new JTextField("30");95.txt_port=new JTextField("6666");96.btn_start=new JButton("启动");97.btn_stop=new JButton("停止");98.btn_send=new JButton("发送");99.btn_stop.setEnabled(false);100.listModel=new DefaultListModel();erList=new JList(listModel);102.103.southPanel=new JPanel(new BorderLayout());104.southPanel.setBorder(new TitledBorder("写消息"));105.southPanel.add(txt_message,"Center");106.southPanel.add(btn_send,"East");107.leftPanel=new JScrollPane(userList);108.leftPanel.setBorder(new TitledBorder("在线用户"));109.110.rightPanel=new JScrollPane(contentArea);111.rightPanel.setBorder(new TitledBorder("消息显示区"));112.113.centerSplit=new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,left Panel,114.rightPanel);115.centerSplit.setDividerLocation(100);116.northPanel=new JPanel();117.northPanel.setLayout(new GridLayout(1,6));118.northPanel.add(new JLabel("人数上限"));119.northPanel.add(txt_max);120.northPanel.add(new JLabel("端口"));121.northPanel.add(txt_port);122.northPanel.add(btn_start);123.northPanel.add(btn_stop);124.northPanel.setBorder(new TitledBorder("配置信息"));125.126.frame.setLayout(new BorderLayout());127.frame.add(northPanel,"North");128.frame.add(centerSplit,"Center");129.frame.add(southPanel,"South");130.frame.setSize(600,400);131.//frame.setSize(Toolkit.getDefaultToolkit().getScreenSize());//设置全屏132.int screen_width=Toolkit.getDefaultToolkit().getScreenSize().wid th;133.int screen_height=Toolkit.getDefaultToolkit().getScreenSize().hei ght;134.frame.setLocation((screen_width-frame.getWidth())/2,135.(screen_height-frame.getHeight())/2);136.frame.setVisible(true);137.138.//关闭窗口时事件139.frame.addWindowListener(new WindowAdapter(){140.public void windowClosing(WindowEvent e){141.if(isStart){142.closeServer();//关闭服务器143.}144.System.exit(0);//退出程序145.}146.});147.148.//文本框按回车键时事件149.txt_message.addActionListener(new ActionListener(){150.public void actionPerformed(ActionEvent e){151.send();152.}153.});154.155.//单击发送按钮时事件156.btn_send.addActionListener(new ActionListener(){157.public void actionPerformed(ActionEvent arg0){158.send();159.}160.});161.162.//单击启动服务器按钮时事件163.btn_start.addActionListener(new ActionListener(){164.public void actionPerformed(ActionEvent e){165.if(isStart){166.JOptionPane.showMessageDialog(frame,"服务器已处于启动状态,不要重复启动!",167."错误",JOptionPane.ERROR_MESSAGE);168.return;169.}170.int max;171.int port;172.try{173.try{174.max=Integer.parseInt(txt_max.getText()); 175.}catch(Exception e1){176.throw new Exception("人数上限为正整数!");177.}178.if(max<=0){179.throw new Exception("人数上限为正整数!");180.}181.try{182.port=Integer.parseInt(txt_port.getText()); 183.}catch(Exception e1){184.throw new Exception("端口号为正整数!"); 185.}186.if(port<=0){187.throw new Exception("端口号为正整数!"); 188.}189.serverStart(max,port);190.contentArea.append("服务器已成功启动!人数上限:"+max+",端口:"+port191.+"\r\n");192.JOptionPane.showMessageDialog(frame,"服务器成功启动!");193.btn_start.setEnabled(false);194.txt_max.setEnabled(false);195.txt_port.setEnabled(false);196.btn_stop.setEnabled(true);197.}catch(Exception exc){198.JOptionPane.showMessageDialog(frame,exc.getMe ssage(),199."错误",JOptionPane.ERROR_MESSAGE);200.}201.}202.});203.204.//单击停止服务器按钮时事件205.btn_stop.addActionListener(new ActionListener(){206.public void actionPerformed(ActionEvent e){207.if(!isStart){208.JOptionPane.showMessageDialog(frame,"服务器还未启动,无需停止!","错误",209.JOptionPane.ERROR_MESSAGE); 210.return;211.}212.try{213.closeServer();214.btn_start.setEnabled(true);215.txt_max.setEnabled(true);216.txt_port.setEnabled(true);217.btn_stop.setEnabled(false);218.contentArea.append("服务器成功停止!\r\n");219.JOptionPane.showMessageDialog(frame,"服务器成功停止!");220.}catch(Exception exc){221.JOptionPane.showMessageDialog(frame,"停止服务器发生异常!","错误",222.JOptionPane.ERROR_MESSAGE);223.}224.}225.});226.}227.228.//启动服务器229.public void serverStart(int max,int port)throws .BindExcepti on{230.try{231.clients=new ArrayList<ClientThread>();232.serverSocket=new ServerSocket(port);233.serverThread=new ServerThread(serverSocket,max); 234.serverThread.start();235.isStart=true;236.}catch(BindException e){237.isStart=false;238.throw new BindException("端口号已被占用,请换一个!"); 239.}catch(Exception e1){240.e1.printStackTrace();241.isStart=false;242.throw new BindException("启动服务器异常!");243.}244.}245.246.//关闭服务器247.@SuppressWarnings("deprecation")248.public void closeServer(){249.try{250.if(serverThread!=null)251.serverThread.stop();//停止服务器线程252.253.for(int i=clients.size()-1;i>=0;i--){254.//给所有在线用户发送关闭命令255.clients.get(i).getWriter().println("CLOSE");256.clients.get(i).getWriter().flush();257.//释放资源258.clients.get(i).stop();//停止此条为客户端服务的线程259.clients.get(i).reader.close();260.clients.get(i).writer.close();261.clients.get(i).socket.close();262.clients.remove(i);263.}264.if(serverSocket!=null){265.serverSocket.close();//关闭服务器端连接266.}267.listModel.removeAllElements();//清空用户列表268.isStart=false;269.}catch(IOException e){270. e.printStackTrace();271.isStart=true;272.}273.}274.275.//群发服务器消息276.public void sendServerMessage(String message){277.for(int i=clients.size()-1;i>=0;i--){278.clients.get(i).getWriter().println("服务器:"+message+"(多人发送)");279.clients.get(i).getWriter().flush();280.}281.}282.283.//服务器线程284.class ServerThread extends Thread{285.private ServerSocket serverSocket;286.private int max;//人数上限287.288.//服务器线程的构造方法289.public ServerThread(ServerSocket serverSocket,int max){290.this.serverSocket=serverSocket;291.this.max=max;292.}293.294.public void run(){295.while(true){//不停的等待客户端的链接296.try{297.Socket socket=serverSocket.accept();298.if(clients.size()==max){//如果已达人数上限299.BufferedReader r=new BufferedReader( 300.new InputStreamReader(socket.getInputStream()));301.PrintWriter w=new PrintWriter(socket 302..getOutputStream());303.//接收客户端的基本用户信息304.String inf=r.readLine();305.StringTokenizer st=new StringTokenize r(inf,"@");er user=new User(st.nextToken(),st .nextToken());307.//反馈连接成功信息308.w.println("MAX@服务器:对不起,"+user.getName()309.+user.getIp()+",服务器在线人数已达上限,请稍后尝试连接!");310.w.flush();311.//释放资源312.r.close();313.w.close();314.socket.close();315.continue;316.}317.ClientThread client=new ClientThread(socket);318.client.start();//开启对此客户端服务的线程319.clients.add(client);320.listModel.addElement(client.getUser().getName( ));//更新在线列表321.contentArea.append(client.getUser().getName() 322.+client.getUser().getIp()+"上线!\r\n");323.}catch(IOException e){324. e.printStackTrace();325.}326.}327.}328.}329.330.//为一个客户端服务的线程331.class ClientThread extends Thread{332.private Socket socket;333.private BufferedReader reader;334.private PrintWriter writer;335.private User user;336.337.public BufferedReader getReader(){338.return reader;339.}340.341.public PrintWriter getWriter(){342.return writer;343.}344.345.public User getUser(){346.return user;347.}348.349.//客户端线程的构造方法350.public ClientThread(Socket socket){351.try{352.this.socket=socket;353.reader=new BufferedReader(new InputStreamReader( socket354..getInputStream()));355.writer=new PrintWriter(socket.getOutputStream()); 356.//接收客户端的基本用户信息357.String inf=reader.readLine();358.StringTokenizer st=new StringTokenizer(inf,"@"); er=new User(st.nextToken(),st.nextToken()); 360.//反馈连接成功信息361.writer.println(user.getName()+user.getIp()+"与服务器连接成功!");362.writer.flush();363.//反馈当前在线用户信息364.if(clients.size()>0){365.String temp="";366.for(int i=clients.size()-1;i>=0;i--){ 367.temp+=(clients.get(i).getUser().getName()+ "/"+clients368..get(i).getUser().getIp())369.+"@";370.}371.writer.println("USERLIST@"+clients.size()+"@"+temp);372.writer.flush();373.}374.//向所有在线用户发送该用户上线命令375.for(int i=clients.size()-1;i>=0;i--){376.clients.get(i).getWriter().println(377."ADD@"+user.getName()+user.getIp( ));378.clients.get(i).getWriter().flush();379.}380.}catch(IOException e){381. e.printStackTrace();382.}383.}384.385.@SuppressWarnings("deprecation")386.public void run(){//不断接收客户端的消息,进行处理。