对于步入编程行业不深的初学者或是已经有所领会的人来说,当学习一项新的技术的时候,非常渴望有一个附上注释完整的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;
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聊天程序
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持考高分网。



