先决条件: 在socket编程中引入线程 在上面的文章中,创建了一个简单的日期时间服务器,它使用线程同时处理多个用户请求。它解释了网络编程中线程的基本概念。同样的概念也可以使用,只需稍加修改即可扩展上述想法,并创建一个类似于facebook messenger、whatsapp等的聊天应用程序。 下面的文章将详细介绍这种应用程序的实现、限制及其解决方案。 在这一集中,我们将讨论服务器端编程(Server.java),在中讨论客户端编程(Client.java) 第二组 .
服务器端编程(Server.java)
1.服务器类: 主服务器实现很简单,与前一篇文章类似。以下几点有助于理解服务器实现:
- 服务器运行一个无限循环来不断接受传入的请求。
- 当请求到来时,它会分配一个新线程来处理通信部分。
- 服务器还将客户机名称存储到一个向量中,以跟踪连接的设备。向量存储与当前请求对应的线程对象。helper类使用这个 矢量 查找要向其发送邮件的收件人的姓名。由于这个向量包含所有流,handler类可以使用它成功地将消息传递给特定的客户端。
- 调用 开始() 方法
2.ClientHandler类: 与前一篇文章类似,我们创建了一个helper类来处理各种请求。这一次,除了套接字和流之外,我们还引入了一个name变量。这将保存连接到服务器的客户端的名称。以下几点有助于理解ClientHandler的实现:
- 每当处理程序收到任何字符串时,它都会将其拆分为消息和收件人部分。为此,它使用Stringtokenizer,并将“#”作为分隔符。这里假设字符串的格式始终为:
message # recipient
- 然后,它会在“已连接的客户端”列表中搜索收件人的姓名,并将其作为向量存储在服务器中。如果它在客户机列表中找到收件人名称,它将在其输出流中转发消息,并在消息前面加上发件人的名称。
JAVA
// Java implementation of Server side // It contains two classes : Server and ClientHandler // Save file as Server.java import java.io.*; import java.util.*; import java.net.*; // Server class public class Server { // Vector to store active clients static Vector<ClientHandler> ar = new Vector<>(); // counter for clients static int i = 0 ; public static void main(String[] args) throws IOException { // server is listening on port 1234 ServerSocket ss = new ServerSocket( 1234 ); Socket s; // running infinite loop for getting // client request while ( true ) { // Accept the incoming request s = ss.accept(); System.out.println( "New client request received : " + s); // obtain input and output streams DataInputStream dis = new DataInputStream(s.getInputStream()); DataOutputStream dos = new DataOutputStream(s.getOutputStream()); System.out.println( "Creating a new handler for this client..." ); // Create a new handler object for handling this request. ClientHandler mtch = new ClientHandler(s, "client " + i, dis, dos); // Create a new Thread with this object. Thread t = new Thread(mtch); System.out.println( "Adding this client to active client list" ); // add this client to active clients list ar.add(mtch); // start the thread. t.start(); // increment i for new client. // i is used for naming only, and can be replaced // by any naming scheme i++; } } } // ClientHandler class class ClientHandler implements Runnable { Scanner scn = new Scanner(System.in); private String name; final DataInputStream dis; final DataOutputStream dos; Socket s; boolean isloggedin; // constructor public ClientHandler(Socket s, String name, DataInputStream dis, DataOutputStream dos) { this .dis = dis; this .dos = dos; this .name = name; this .s = s; this .isloggedin= true ; } @Override public void run() { String received; while ( true ) { try { // receive the string received = dis.readUTF(); System.out.println(received); if (received.equals( "logout" )){ this .isloggedin= false ; this .s.close(); break ; } // break the string into message and recipient part StringTokenizer st = new StringTokenizer(received, "#" ); String MsgToSend = st.nextToken(); String recipient = st.nextToken(); // search for the recipient in the connected devices list. // ar is the vector storing client of active users for (ClientHandler mc : Server.ar) { // if the recipient is found, write on its // output stream if (mc.name.equals(recipient) && mc.isloggedin== true ) { mc.dos.writeUTF( this .name+ " : " +MsgToSend); break ; } } } catch (IOException e) { e.printStackTrace(); } } try { // closing resources this .dis.close(); this .dos.close(); } catch (IOException e){ e.printStackTrace(); } } } |
输出:
New client request received : Socket[addr=/127.0.0.1,port=61818,localport=1234]Creating a new handler for this client...Adding this client to active client listNew client request received : Socket[addr=/127.0.0.1,port=61819,localport=1234]Creating a new handler for this client...Adding this client to active client list
限制: 虽然上面的服务器实现能够处理大多数场景,但上面定义的方法存在一些缺点。
- 从上述项目中可以清楚地看到: 如果客户端数量增加,搜索时间就会增加 在handler类中。为了避免这种增加,可以使用两个哈希映射。以名称为键,以活动列表中的索引为值。另一个是索引作为键,关联的处理程序对象作为值。通过这种方式,我们可以快速查找两个哈希映射以匹配收件人。让读者来实现这个黑客,以提高实现的效率。
- 另一件需要注意的事情是,这个实现 当用户断开与服务器的连接时无法正常工作 。由于在此实现中未处理断开连接,因此会引发很多错误。它可以像前面的基本TCP示例一样轻松实现。它也留给读者在程序中实现此功能。
客户机程序(client.java)与之前的文章有很大的不同,因此将在本系列的第2集中讨论。
相关文章: 多线程聊天应用程序|集2
本文由 Rishabh Mahrsee .如果你喜欢GeekSforgek,并想贡献自己的力量,你也可以使用 写极客。组织 或者把你的文章寄去评论-team@geeksforgeeks.org.看到你的文章出现在Geeksforgeks主页上,并帮助其他极客。 如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请写下评论。