CurtisWalsh пре 4 година
комит
57001d2ff0

+ 5 - 0
.idea/codeStyles/codeStyleConfig.xml

@@ -0,0 +1,5 @@
+<component name="ProjectCodeStyleConfiguration">
+  <state>
+    <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
+  </state>
+</component>

+ 6 - 0
.idea/misc.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/out" />
+  </component>
+</project>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/OneToOne.iml" filepath="$PROJECT_DIR$/OneToOne.iml" />
+    </modules>
+  </component>
+</project>

+ 119 - 0
.idea/workspace.xml

@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ChangeListManager">
+    <list default="true" id="a967317c-7b81-4f6a-b7e9-51cdaf77c31b" name="Default Changelist" comment="" />
+    <option name="SHOW_DIALOG" value="false" />
+    <option name="HIGHLIGHT_CONFLICTS" value="true" />
+    <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
+    <option name="LAST_RESOLUTION" value="IGNORE" />
+  </component>
+  <component name="CodeStyleSettingsInfer">
+    <option name="done" value="true" />
+  </component>
+  <component name="FileTemplateManagerImpl">
+    <option name="RECENT_TEMPLATES">
+      <list>
+        <option value="Class" />
+      </list>
+    </option>
+  </component>
+  <component name="ProjectCodeStyleSettingsMigration">
+    <option name="version" value="1" />
+  </component>
+  <component name="ProjectId" id="1lzdhQWgZ3MTTc2jERQKKo6FK3L" />
+  <component name="ProjectViewState">
+    <option name="showExcludedFiles" value="true" />
+    <option name="showLibraryContents" value="true" />
+  </component>
+  <component name="PropertiesComponent">
+    <property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
+    <property name="WebServerToolWindowFactoryState" value="false" />
+    <property name="aspect.path.notification.shown" value="true" />
+    <property name="last_opened_file_path" value="$PROJECT_DIR$/../多人聊天+用户在线" />
+    <property name="settings.editor.selected.configurable" value="editor.preferences.fonts.default" />
+  </component>
+  <component name="RunManager" selected="Application.ClientChatMain">
+    <configuration name="ClientChatMain" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true">
+      <option name="MAIN_CLASS_NAME" value="ClientChatMain" />
+      <module name="OneToOne" />
+      <method v="2">
+        <option name="Make" enabled="true" />
+      </method>
+    </configuration>
+    <configuration name="ServerChatMain" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true">
+      <option name="MAIN_CLASS_NAME" value="ServerChatMain" />
+      <module name="OneToOne" />
+      <method v="2">
+        <option name="Make" enabled="true" />
+      </method>
+    </configuration>
+    <recent_temporary>
+      <list>
+        <item itemvalue="Application.ClientChatMain" />
+        <item itemvalue="Application.ServerChatMain" />
+      </list>
+    </recent_temporary>
+  </component>
+  <component name="SvnConfiguration">
+    <configuration />
+  </component>
+  <component name="TaskManager">
+    <task active="true" id="Default" summary="Default task">
+      <changelist id="a967317c-7b81-4f6a-b7e9-51cdaf77c31b" name="Default Changelist" comment="" />
+      <created>1608603972443</created>
+      <option name="number" value="Default" />
+      <option name="presentableId" value="Default" />
+      <updated>1608603972443</updated>
+      <workItem from="1608603975890" duration="2481000" />
+      <workItem from="1608606905181" duration="943000" />
+      <workItem from="1608684253226" duration="18264000" />
+      <workItem from="1608792815791" duration="44000" />
+      <workItem from="1608857593367" duration="1122000" />
+      <workItem from="1609125120242" duration="5702000" />
+      <workItem from="1609289263576" duration="622000" />
+      <workItem from="1609292747184" duration="579000" />
+      <workItem from="1609293541541" duration="602000" />
+    </task>
+    <servers />
+  </component>
+  <component name="TypeScriptGeneratedFilesManager">
+    <option name="version" value="1" />
+  </component>
+  <component name="WindowStateProjectService">
+    <state x="574" y="121" key="#com.intellij.ide.util.MemberChooser" timestamp="1608772025746">
+      <screen x="0" y="0" width="1536" height="824" />
+    </state>
+    <state x="574" y="121" key="#com.intellij.ide.util.MemberChooser/0.0.1536.824@0.0.1536.824" timestamp="1608772025746" />
+    <state x="549" y="170" key="FileChooserDialogImpl" timestamp="1609293326070">
+      <screen x="0" y="0" width="1536" height="824" />
+    </state>
+    <state x="549" y="170" key="FileChooserDialogImpl/0.0.1536.824@0.0.1536.824" timestamp="1609293326070" />
+    <state width="1493" height="210" key="GridCell.Tab.0.bottom" timestamp="1609296452720">
+      <screen x="0" y="0" width="1536" height="824" />
+    </state>
+    <state width="1493" height="210" key="GridCell.Tab.0.bottom/0.0.1536.824@0.0.1536.824" timestamp="1609296452720" />
+    <state width="1493" height="210" key="GridCell.Tab.0.center" timestamp="1609296452720">
+      <screen x="0" y="0" width="1536" height="824" />
+    </state>
+    <state width="1493" height="210" key="GridCell.Tab.0.center/0.0.1536.824@0.0.1536.824" timestamp="1609296452720" />
+    <state width="1493" height="210" key="GridCell.Tab.0.left" timestamp="1609296452719">
+      <screen x="0" y="0" width="1536" height="824" />
+    </state>
+    <state width="1493" height="210" key="GridCell.Tab.0.left/0.0.1536.824@0.0.1536.824" timestamp="1609296452719" />
+    <state width="1493" height="210" key="GridCell.Tab.0.right" timestamp="1609296452720">
+      <screen x="0" y="0" width="1536" height="824" />
+    </state>
+    <state width="1493" height="210" key="GridCell.Tab.0.right/0.0.1536.824@0.0.1536.824" timestamp="1609296452720" />
+    <state x="-123" y="29" key="SettingsEditor" timestamp="1608607843212">
+      <screen x="0" y="0" width="1536" height="824" />
+    </state>
+    <state x="-123" y="29" key="SettingsEditor/0.0.1536.824@0.0.1536.824" timestamp="1608607843212" />
+    <state x="431" y="145" width="672" height="678" key="search.everywhere.popup" timestamp="1608687549237">
+      <screen x="0" y="0" width="1536" height="824" />
+    </state>
+    <state x="431" y="145" width="672" height="678" key="search.everywhere.popup/0.0.1536.824@0.0.1536.824" timestamp="1608687549237" />
+  </component>
+  <component name="se.expertsystem.intellij.aop.aspectj.AspectJProjectComponent">
+    <setting name="isActivated" value="false" />
+  </component>
+</project>

+ 11 - 0
OneToOne.iml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 3 - 0
OneToOne.properties

@@ -0,0 +1,3 @@
+serverPort=8888
+clientIp=127.0.0.1
+clientPort=8888

BIN
out/production/OneToOne/ClientChatMain.class


BIN
out/production/OneToOne/ServerChatMain.class


+ 162 - 0
src/ClientChatMain.java

@@ -0,0 +1,162 @@
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.io.*;
+import java.net.Socket;
+import java.util.Properties;
+
+//说明:如果一个类,需要有界面的显示,那么这个类就需要继承JFrame。此时,该类就可以被称为 “ 窗体类 ” 。
+//1.定义窗体中的组件。
+//2.在构造方法中初始化窗体的组件。
+//3.使用网络编程完成数据的传输(TCP,UDP协议)。
+//4.实现 “ 发送 ” 按钮的监听点击事件。需要注意的是,文本拼接数据时实现自己换行,不要在发送数据中使用System.lineSeparator()换行。
+//这样会导致bw.newLine() 与 System.lineSeparator() 两个换行,导致使用BufferedWriter一行一行读取时无法正确的辨别需要的换行。
+//5.实现回车键发送数据。
+public class ClientChatMain extends JFrame implements ActionListener , KeyListener {
+    public static void main(String[] args) {
+        //调用构造方法
+        new ClientChatMain();
+    }
+    //属性
+    //文本域
+    private JTextArea jta;
+    //滚动条
+    private JScrollPane jsp;
+    //面板
+    private JPanel jp;
+    //文本框
+    private JTextField jtf;
+    //按钮
+    private JButton jb;
+
+    //输出流
+    private BufferedWriter bw = null;
+
+    //客户端的 Ip 地址
+    private static String clientIp;
+    //客户端的端口号
+    private static int clientPort;
+
+    //静态代码块加载外部配置文件
+    static {
+        Properties prop = new Properties();
+        try {
+            prop.load(new FileReader("OneToOne.properties"));
+            clientIp = prop.getProperty("clientIp");
+            clientPort = Integer.parseInt(prop.getProperty("clientPort"));
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    //构造方法
+    public ClientChatMain() {
+        //初始化组件
+        //文本域
+        jta = new JTextArea();
+        //设置文本域不可编辑
+        jta.setEditable(false);
+        //滚动条  注意:需要将文本域添加到滚动条中,实现滚动效果。
+        jsp = new JScrollPane(jta);
+        //面板
+        jp = new JPanel();
+        //文本框  需要给长度
+        jtf= new JTextField(10);
+        //按钮  需要写按钮功能
+        jb = new JButton("发送");
+        //注意:需要将文本框和按钮添加到面板中
+        jp.add(jtf);
+        jp.add(jb);
+
+        //注意:需要将滚动条与面板添加到窗体中,并设置布局。
+        this.add(jsp, BorderLayout.CENTER);
+        this.add(jp,BorderLayout.SOUTH);
+
+        //注意:需要设置 “ 标题,大小,位置,关闭,是否可见 ”
+        this.setTitle("OneToOne聊天 客户端");
+        this.setSize(500,500);
+        this.setLocation(1000,300);
+        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        this.setVisible(true);
+
+        /*********************** TCP 客户端 start ***********************/
+        //给发送按钮绑定一个监听点击事件
+        jb.addActionListener(this);
+        //给文本框绑定键盘点击事件
+        jtf.addKeyListener(this);
+        try{
+        //1.创建一个客户端的套接字(尝试链接)
+        Socket socket = new Socket(clientIp,clientPort);
+
+        //2.获取 Socket 通道的输入流
+        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+
+        //3.获取 Socket 通道的输出流
+        bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
+
+        //循环读取数据并拼接到文本域中
+        String line = null;
+        while ((line = br.readLine()) != null){
+            jta.append(line + System.lineSeparator());
+        }
+
+        //4.关闭 Socket 通道
+        socket.close();
+
+    }catch (Exception e){
+        e.printStackTrace();
+    }
+
+        /*********************** TCP 客户端 end  ***********************/
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        sendDataToSocket();
+    }
+
+    //行为
+
+    @Override
+    public void keyPressed(KeyEvent e) {
+        //回车键
+        if (e.getKeyCode() == KeyEvent.VK_ENTER) {
+            System.out.println(e);
+            //发送数据到 socket 通道中
+            sendDataToSocket();
+        }
+    }
+
+    //定义一个方法,实现将数据发送到 socket 通道中
+    private void sendDataToSocket(){
+        //1.获取文本框中发送的内容
+        String text = jtf.getText();
+        //2.拼接需要发送的数据内容
+        text = "服务端对客户端说:" + text ;
+        //3.发送之前自己显示
+        jta.append(text + System.lineSeparator());
+        try {
+            //4.发送
+            bw.write(text);
+            bw.newLine();
+            bw.flush();
+            //5.清空文本框内容
+            jtf.setText("");
+        } catch (IOException ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    @Override
+    public void keyTyped(KeyEvent e) {
+    }
+
+    @Override
+    public void keyReleased(KeyEvent e) {
+    }
+
+
+}

+ 170 - 0
src/ServerChatMain.java

@@ -0,0 +1,170 @@
+import javax.swing.*;
+import javax.xml.soap.Text;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.io.*;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.Properties;
+
+//说明:如果一个类,需要有界面的显示,那么这个类就需要继承JFrame。此时,该类就可以被称为 “ 窗体类 ” 。
+//1.定义窗体中的组件。
+//2.在构造方法中初始化窗体的组件。
+//3.使用网络编程完成数据的传输(TCP,UDP协议)。
+//4.实现 “ 发送 ” 按钮的监听点击事件。需要注意的是,文本拼接数据时实现自己换行,不要在发送数据中使用System.lineSeparator()换行。
+//这样会导致bw.newLine() 与 System.lineSeparator() 两个换行,导致使用BufferedWriter一行一行读取时无法正确的辨别需要的换行。
+//5.实现回车键发送数据。
+public class ServerChatMain extends JFrame implements ActionListener , KeyListener {
+    public static void main(String[] args) {
+        //调用构造方法
+        new ServerChatMain();
+    }
+    //属性
+    //文本域
+    private JTextArea jta;
+    //滚动条
+    private JScrollPane jsp;
+    //面板
+    private JPanel jp;
+    //文本框
+    private JTextField jtf;
+    //按钮
+    private JButton jb;
+
+    //输出流
+    private BufferedWriter bw = null;
+    //服务端的端口号
+    private static int serverPort;
+    //使用 Static 静态代码块读取外部配置文件。
+    //特点1:在类加载的时候自动执行
+    //特点2:一个类只会被加载一次,因为静态代码块在程序中仅会被执行一次。
+    static {
+        Properties prop = new Properties();
+        try {
+            //加载
+            prop.load(new FileReader("OneToOne.properties"));
+            //给属性赋值
+            serverPort = Integer.parseInt(prop.getProperty("serverPort"));
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    //构造方法
+    public ServerChatMain() {
+        //初始化组件
+        //文本域
+        jta = new JTextArea();
+        //设置文本域不可编辑
+        jta.setEditable(false);
+        //滚动条  注意:需要将文本域添加到滚动条中,实现滚动效果。
+        jsp = new JScrollPane(jta);
+        //面板
+        jp = new JPanel();
+        //文本框  需要给长度
+        jtf= new JTextField(10);
+        //按钮  需要写按钮功能
+        jb = new JButton("发送");
+        //注意:需要将文本框和按钮添加到面板中
+        jp.add(jtf);
+        jp.add(jb);
+
+        //注意:需要将滚动条与面板添加到窗体中,并设置布局。
+        this.add(jsp, BorderLayout.CENTER);
+        this.add(jp,BorderLayout.SOUTH);
+
+        //注意:需要设置 “ 标题,大小,位置,关闭,是否可见 ”
+        this.setTitle("OneToOne聊天 服务端");
+        this.setSize(500,500);
+        this.setLocation(400,300);
+        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        this.setVisible(true);
+
+        /*********************** TCP 服务端 start ***********************/
+        //给发送按钮绑定一个监听点击事件
+        jb.addActionListener(this);
+        //给文本框绑定键盘点击事件
+        jtf.addKeyListener(this);
+        try{
+            //1.创建一个服务端的套接字
+            ServerSocket serverSocket = new ServerSocket(serverPort);
+
+            //2.等待客户端的连接
+            Socket socket = serverSocket.accept();
+
+            //3.获取 Socket 通道的输入流(输入流是实现读取数据的,一行一行地取)BufferedReader -> readLine();
+            //InputStream in = socket.getInputStream();
+            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+
+            //4.获取 Socket 通道的输出流(输出流实现写出数据,也是写一行换一行,刷新)BufferedWriter -> newLine();
+            //问题:什么时候需要写出数据??? 当用户点击 “ 发送 ” 按钮的时候才需要写出数据。
+            bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
+
+            //循环读取数据并拼接到文本域中
+            String line = null;
+            while ((line = br.readLine()) != null){
+                //将读取的数据拼接到文本域中显示
+                jta.append(line + System.lineSeparator());  //换行
+            }
+            //5.关闭 severSocket 通道
+            serverSocket.close();
+
+        }catch (IOException e){
+            e.printStackTrace();
+        }
+
+
+        /*********************** TCP 服务端 end  ***********************/
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        //System.out.println("发送按钮被点击了。。。");
+        sendDataToSocket();
+    }
+
+    //行为
+
+    @Override
+    public void keyPressed(KeyEvent e) {
+    //回车键
+        if (e.getKeyCode() == KeyEvent.VK_ENTER) {
+            System.out.println(e);
+            //发送数据到 socket 通道中
+            sendDataToSocket();
+        }
+    }
+
+    //定义一个方法,实现将数据发送到 socket 通道中
+    private void sendDataToSocket(){
+        //1.获取文本框中发送的内容
+        String text = jtf.getText();
+        //2.拼接需要发送的数据内容
+        text = "服务端对客户端说:" + text ;
+        //3.发送之前自己显示
+        jta.append(text + System.lineSeparator());
+        try {
+            //4.发送
+            bw.write(text);
+            bw.newLine();
+            bw.flush();
+            //5.清空文本框内容
+            jtf.setText("");
+        } catch (IOException ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    @Override
+    public void keyTyped(KeyEvent e) {
+    }
+
+    @Override
+    public void keyReleased(KeyEvent e) {
+    }
+
+}
+