热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

java实现基于Tcp的socket聊天程序

这篇文章主要为大家详细介绍了java实现基于Tcp的socket聊天程序,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

对于步入编程行业不深的初学者或是已经有所领会的人来说,当学习一项新的技术的时候,非常渴望有一个附上注释完整的Demo。本人深有体会,网上的例子多到是很多,但是很杂不完整,写代码这种东西来不得半点马虎,要是错了一点,那也是运行不了的。这对于初学者来说更加的头疼,因为他根本不知道错在哪里,盲目的改只能错上加错。最后不得不去找找看看有没有能够直接运行的例子再加以模仿。

下面是博主在学习Java的socket时写的一个完整的例子,并且带上了完整的注释。它是一个简单的聊天程序,但是它可以设置任意多用户同时登录,然后相互两两交流。博主仅仅在自己电脑上实现同时登录,然后两两相互交流。

程序的大体思路是这样的:

①该用户作为服务端也就是被请求连接端和主动请求连接其他端时不一样的,其次有可能被其他的用户连接很多次,那么你作为服务端,就会有很多连接,同样的道理,你作为客户端也会有很多的连接。为了程序更加通俗易懂,博主写的时候,设置了很多容器,将不一样的东西分开放置。做到解耦合,不然到后面自己都分不清了。

②你可以一次写两个类,client1,client2,,client1先作为服务端,client2作为客户端,客户端去连接服务端,从而实现client1的服务端功能和client2的客户端功能。每次实现一个功能就先将服务端和客户端的功能整合一下,互换角色,看是否存在错误。

③在实现了两个用户的情况下再去写第三个类client3,代码就是复制粘贴。当然你也可以直接创建一个client3的类,然后直接在类的main方法中改了端口号,和用户名就行。第三个实现后,第四个第五个也就实了。

下面是具体的代码:

package jack;
 
import java.awt.List;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.time.format.TextStyle;
import java.util.ArrayList;
 
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.plaf.basic.BasicTabbedPaneUI.TabbedPaneLayout;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter.DEFAULT;
 
import org.omg.CORBA.PRIVATE_MEMBER;
/**
 * 被请求连接时称为服务器;主动连接对方时称为客户端。
 * @author Administrator
 *
 */
public class Client4 extends JFrame implements ActionListener{
 
 private static int sign = 0;    //用来记录选项卡的标签,0标示第一个。
 private JToolBar toolBar1,toolBar2;
 private JLabel waitPortLabel,hostLabel,portLabel;
 private JTextField waitPortTF,hostTF,portTF,sendTF;
 private JTabbedPane tab;
 private JButton sendB,leaveB,deleteB,connB;
 private ArrayList serverThreads; //存放服务器线程的容器。即存放被请求连接时所创建的线程的容器。
 private ArrayList clientThreads; //存放客户端线程的容器。即存放主动连接对方时所创建的线程的容器。
 private ArrayList servers;  //服务对象的容器。
 private ArrayList serverTextAreas; //作为服务器时,存放所创建的对话记录显示区域的容器。
 private ArrayList clientTextAreas; //作为客户端时,岑芳所创建的对话记录显示区域的容器。
 private ArrayList serverSockets;  //存放被请求连接时所创建的socket的容器。
 private ArrayList clientSockets; //存放主动请求连接时所创立的socket的容器。
 private ArrayList serverPWriters;  //存放服务端输出流对象的容器。
 private ArrayList serverBReaders; //存放服务端输入流对象的容器。
 private ArrayList clientPWriters;  //存放客户端输出流对象的容器。
 private ArrayList clientBReaders; //存放客户端输入流对象的容器。
 private ArrayList ports;  //存放作为服务器时已连接的端口。
 private int port = 2041; //指定自己开放的第一个端口号,方便其他人连接。
 private String name;     //储存自己的名称。
 
 public Client4(String name) throws IOException{
 super(name);
 this.name = name;     
 toolBar1 = new JToolBar();
 toolBar2 = new JToolBar();
 waitPortLabel = new JLabel("等待端口");
 hostLabel = new JLabel("主机");
 portLabel = new JLabel("端口");
 waitPortTF = new JTextField("2041");
 hostTF = new JTextField("127.0.0.1");
 portTF = new JTextField(5);
 sendTF = new JTextField();
 tab = new JTabbedPane();
 sendB = new JButton("发送");
 leaveB = new JButton("离线");
 deleteB = new JButton("删除页");
 cOnnB= new JButton("连接端口");
 
 servers = new ArrayList();
 serverTextAreas = new ArrayList();
 clientTextAreas = new ArrayList();
 serverSockets = new ArrayList();
 clientSockets = new ArrayList();
 serverPWriters = new ArrayList();
 serverBReaders = new ArrayList();
 clientPWriters = new ArrayList();
 clientBReaders = new ArrayList();
 serverThreads = new ArrayList();
 clientThreads = new ArrayList();
 ports = new ArrayList();
 
 toolBar1.add(waitPortLabel);
 toolBar1.add(waitPortTF);
 toolBar1.add(hostLabel);
 toolBar1.add(hostTF);
 toolBar1.add(portLabel);
 toolBar1.add(portTF);
 toolBar1.add(connB);
 
 toolBar2.add(sendTF);
 toolBar2.add(sendB);
 toolBar2.add(leaveB);
 toolBar2.add(deleteB);
 
 waitPortTF.setEnabled(false);   //设置等待的textfield不可以编辑。
 hostTF.setEnabled(false); //设置连接的ip地址不可编辑,当然这里可以更改成其他电脑的ip地址。
 this.getContentPane().add(toolBar1, "North"); //添加工具栏到最上方。
 this.getContentPane().add(tab,"Center"); //添加选项卡窗格。
 this.getContentPane().add(toolBar2,"South"); //添加工具栏到下方。
 
 this.setBounds(200, 200, 350, 300);
 this.setVisible(true);
 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 
 sendB.addActionListener(this);
 leaveB.addActionListener(this);
 deleteB.addActionListener(this);
 connB.addActionListener(this);
 
 //主线程进入之后 在server.accept()阻塞等待客户端来连接。
 while(true){
 ServerSocket server = new ServerSocket(port); //作为服务器,开发自己供连接的端口。
 servers.add(server);  
 Socket serverSocket = server.accept();  //等待对方连接。
 serverSockets.add(serverSocket);
 ports.add(port);   //将已连接的端口加入容器。
 PrintWriter serverPWriter = new PrintWriter(serverSocket.getOutputStream(),true);//初始化输出流对象。
 serverPWriters.add(serverPWriter);
 BufferedReader serverBReader = new BufferedReader(new InputStreamReader(serverSocket.getInputStream()));//初始化输入流对象。
 serverBReaders.add(serverBReader);
 serverPWriter.println("连接"+name+"成功");  //将连接成功的消息发送给请求方,提醒对方连接成功。
 serverPWriter.println(name);  //将自己的名称发送给对方,方便对方设置选项卡的名称。
 String cOntent= serverBReader.readLine();  //此时对方也发送了上面两条消息过来。读入对方发送过来的提醒消息。
 String name2 = serverBReader.readLine(); //读取对方的名称。方便后面设置选项卡的名称。
 System.out.println(content);
 System.out.println(name2);
 MyJTextArea serverTextArea = new MyJTextArea(sign); 
 sign++;      //new了一个textArea后,sign自动增加1,好和选项卡对应,
       //知道这个选项卡加到哪个容器了,是服务器的还是客户端的。
 serverTextAreas.add(serverTextArea);
 this.tab.addTab(name2,new JScrollPane(serverTextArea));//在选项卡窗格中添加一个选项卡。
 serverTextArea.setEditable(false); //设置对话记录显示区域不可编辑。
 serverTextArea.setLineWrap(true); //设置对话记录显示区域自动换行。
 serverTextArea.append(content+"\n"); //在对话记录区域输出连接成功这条消息。
 ChatThread thread = new ChatThread(); //new了一个线程去执行run方法,用于和对方交流,对方也会开启一个线程来和你交流。
  //这里要开启新线程的原因是main线程经过一轮后会在上面accept方法处阻塞。
 serverThreads.add(thread);
 thread.start();     //启动该线程,方便接收对方发来的消息。
 port++;  //端口号加一,开放下一个供连接的端口。
 waitPortTF.setText(port+"");   //更新显示等待的下个端口。
 }
 }
 
 private class ChatThread extends Thread {
 
 private String[] serverCOntents= new String[10]; //当作为服务端时,用来存放相互发送消息时的一句话。
 private String[] clientCOntents= new String[10]; //当作为客户端时,用来存放相互发送消息时的一句话。
 private boolean isServerThread = true;  //判断当前在执行run方法的线程是不是服务端线程。
 
 @Override
 public void run() {
 
 while(true){
 if(serverThreads.size()>0){ //判断当前的线程是否是服务线程。先判断是否大于0,是为了防止serverThreads 
 for(int i=0;i0){   //判断当前的线程是否是客户线程。 先判断是否大于0,是为了防止clientThreads
 for(int i=0;i0){    //如果是被请求连接时而创建的选项卡要发送消息。即服务端。
 for(int i=0;i0){    //如果是客户端。
 for(int i=0;i0){      //如果是服务端。
 for(int i=0;i0){      //如果是客户端。
 for(int i=0;i0){ //为了防止下面的serverTextAreas数组越界。
 for(int i=0;i0){ //为了防止下面的serverTextAreas数组越界。
 for(int i=0;i

效果图:

源码下载:Java基于Tcp的socket聊天程序

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文介绍了使用AJAX的POST请求实现数据修改功能的方法。通过ajax-post技术,可以实现在输入某个id后,通过ajax技术调用post.jsp修改具有该id记录的姓名的值。文章还提到了AJAX的概念和作用,以及使用async参数和open()方法的注意事项。同时强调了不推荐使用async=false的情况,并解释了JavaScript等待服务器响应的机制。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • 胡蜂能进行逻辑推理的研究成果
    最新研究表明,胡蜂具备一定的逻辑推理能力,能够进行传递性推理。研究人员通过实验发现,胡蜂在避免电击的测试中,能够正确选择符合逻辑的选项。这项研究成果对于了解无脊椎动物的认知能力具有重要意义,也为解析胡蜂社会结构的进化提供了线索。 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • 本文是关于自学Android的笔记,包括查看类的源码的方法,活动注册的必要性以及布局练习的重要性。通过学习本文,读者可以了解到在自学Android过程中的一些关键点和注意事项。 ... [详细]
author-avatar
你的依靠isme
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有