java socket实现服务端,客户端简单网络通信。Chat
2021-06-14 17:06
标签:ons relative 重要 field values desc 点击事件 utc ane 之前写的实现简单网络通信的代码,有一些严重bug。后面详细写。 根据上次的代码,主要增加了用户注册,登录页面,以及实现了实时显示当前在登录状态的人数。并解决一些上次未发现的bug。(主要功能代码参见之前随笔 https://www.cnblogs.com/yuqingsong-cheng/p/12740307.html) 实现用户注册登录就需要用到数据库,因为我主要在学Sql Server。Sql Server也已支持Linux系统。便先在我的电脑Ubuntu系统下进行安装配置。 链接:https://docs.microsoft.com/zh-cn/sql/linux/quickstart-install-connect-red-hat?view=sql-server-ver15 Sql Server官网有各个系统的安装指导文档,所以按照正常的安装步骤,一切正常安装。 可放到服务器中却出现了问题。阿里云学生服务器是2G内存的(做活动外加学生证,真的很香。但内存有点小了)。sqlserer需要至少2G内存。所以只能放弃SqlServer,转向Mysql。 同样根据MySql的官方指导文档进行安装。但进行远程连接却需要一些“乱七八糟”的配置,于是开始“面向百度连接”,推荐一个解决方案,https://blog.csdn.net/ethan__xu/article/details/89320614 适用于mysql8.0以上版本。 数据库部分解决,开始写关于登录,注册类。登录注册部分新开了一个端口进行socket连接。由于功能较简单,所以只用到了插入,查询语句。 客户端读入用户输入的登录,注册信息,发送至服务端,服务端在连接数据库进行查询/插入操作,将结果发送至客户端。 实例代码 因为服务端需要放到服务器中,所以就删去了服务端的用户界面。 客户端,登录界面与服务带进行socket连接,发送用户信息,并读取返回的信息。 主要代码: 连接服务端:第一次写的时候连接方法是Boolean类型,但只适用于登录的信息判断,当注册时需要判断昵称是否重复,密码昵称是否为空等不同的返回信息,(服务端代码有相应的判断字符串返回,参上)于是该为将连接方法改为String类型。 用户注册界面,主要代码: 用户登录,注册部分至此完毕。 实时显示人数,主要是向客户端返回存储socket对象的泛型数组大小。在当有新的客户端连接之后调用此方法,当有用户断开连接后调用此方法。 说说Bug 用户每次断开连接之前都没有先进行socket的关闭,服务端也没有移除相应的socket对象,这就导致当服务端再逐个发送至每个客户端,便找不到那个关闭的socket对象,会产生"write error" 。 所以便需要再客户端断开时移除相应的socket对象,查看java API文档,并没有找到在服务端可以判断客户端socket是否关闭的方方法。 便想到了之前看的方法。(虽然感觉这样麻烦了一步,但没找到更好的办法)。于是在点击退出按钮,或关闭面板时向服务端发送一个"bye"字符,当服务端读取到此字符时便知道客户端要断开连接了,从而退出循环读取操作,移除对应的socket对象。 文件的流的关闭,移除也是如此,不在赘述。 文件流还有一个问题,正常登录不能进行第二次文件传输。(第一次写的时候可能我只测试了一次,没有找到bug。哈哈哈哈) 解决这个问题耽搁了好久(太cai了,哈哈哈哈) 原来的代码,服务端读取并发送部分(也可参加看之前的随笔) read()方法:API文档的介绍 当读取到文件末尾时会返回-1,可以看到while循环也是当len等于-1时结束循环,然而事与愿违。在debug时(忘记截图)发现,只要客户端的输出流不关闭,服务端当文件的读取完毕后会一直阻塞在 至此结束 感觉文件的传输读取仍然存在问题,下次继续完善。 部分界面截图 java socket实现服务端,客户端简单网络通信。Chat 标签:ons relative 重要 field values desc 点击事件 utc ane 原文地址:https://www.cnblogs.com/yuqingsong-cheng/p/12822628.html 1 package logindata;
2
3 import java.io.DataInputStream;
4 import java.io.DataOutputStream;
5 import java.io.IOException;
6 import java.net.ServerSocket;
7 import java.net.Socket;
8 import java.sql.Connection;
9 import java.sql.DriverManager;
10 import java.sql.ResultSet;
11 import java.sql.SQLException;
12 import java.sql.Statement;
13 import java.util.ArrayList;
14
15 public class LoginData implements Runnable{
16
17 static ArrayList
1 import file.File;
2 import logindata.LoginData;
3 import server.Server;
4
5 public class ServerStart_View {
6
7 private static Server server = new Server();
8 private static File file = new File();
9 private static LoginData loginData = new LoginData();
10 public static void main(String [] args) {
11 ServerStart_View frame = new ServerStart_View();
12 server.get(frame);
13 Thread thread = new Thread(server);
14 thread.start();
15
16 Thread thread2 = new Thread(file);
17 thread2.start();
18
19 Thread thread3 = new Thread(loginData);
20 thread3.start();
21 }
22 public void setText(String AllName,String string) {
23 System.out.println(AllName+" : "+string);
24 }
25 }
1 public class Login_View extends JFrame {
2
3 public static String AllName=null;
4 static Login_View frame;
5 private JPanel contentPane;
6 private JTextField textField;
7 private JTextField textField_1;
8 JOptionPane optionPane = new JOptionPane();
9 private final Action action = new SwingAction();
10 private JButton btnNewButton_1;
11 private final Action action_1 = new SwingAction_1();
12 private JLabel lblNewLabel_2;
13
14 /**
15 * Launch the application.
16 */
17 public static void main(String[] args) {
18 EventQueue.invokeLater(new Runnable() {
19 public void run() {
20 try {
21 frame = new Login_View();
22 frame.setVisible(true);
23 frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
24 } catch (Exception e) {
25 e.printStackTrace();
26 }
27 }
28 });
29 }
30
31 ..................
32 ..................
33 ..................
34
35 private class SwingAction extends AbstractAction {
36 public SwingAction() {
37 putValue(NAME, "登录");
38 putValue(SHORT_DESCRIPTION, "点击登录");
39 }
40 public void actionPerformed(ActionEvent e) {
41 String text = textField.getText();
42 String text2 = textField_1.getText();
43 // System.out.println(text+text2);
44 // boolean boo=false;
45 String boo=null;
46 try {
47 boo = DataJudge.Judge(6567,text,text2,"login");
48 } catch (IOException e1) {
49 e1.printStackTrace();
50 }
51 if(boo.equals("true")) {
52 ClientStart_View.main1();
53 AllName = text; //保存用户名
54 frame.dispose(); //void dispose() 释放此this Window,其子组件和所有其拥有的子级使用的所有本机屏幕资源 。
55 }else {
56 optionPane.showConfirmDialog
57 (contentPane, "用户名或密码错误,请再次输入", "登录失败",JOptionPane.OK_CANCEL_OPTION);
58 }
59 }
60 }
61
62 private class SwingAction_1 extends AbstractAction {
63 public SwingAction_1() {
64 putValue(NAME, "注册");
65 putValue(SHORT_DESCRIPTION, "点击进入注册页面");
66 }
67 public void actionPerformed(ActionEvent e) {
68 Registered_View registered = new Registered_View(Login_View.this);
69 registered.setLocationRelativeTo(rootPane);
70 registered.setVisible(true);
71 }
72 }
73 }
1 import java.io.DataInputStream;
2 import java.io.DataOutputStream;
3 import java.io.IOException;
4 import java.net.Socket;
5 import java.net.UnknownHostException;
6
7 public class DataJudge {
8
9 /*public static boolean Judge(int port,String name,String password,String judge) throws UnknownHostException, IOException {
10
11 Socket socket = new Socket("127.0.0.1", port);
12 DataInputStream inputStream = new DataInputStream(socket.getInputStream());
13 DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
14
15 outputStream.writeUTF(name);
16 outputStream.writeUTF(password);
17 outputStream.writeUTF(judge);
18
19 boolean readBoolean = inputStream.readBoolean();
20
21 outputStream.close();
22 inputStream.close();
23 socket.close();
24 return readBoolean;
25 }*/
26
27 public static String Judge(int port,String name,String password,String judge) throws UnknownHostException, IOException {
28
29 //连接服务端数据库部分
30 Socket socket = new Socket("127.0.0.1", port);
31 DataInputStream inputStream = new DataInputStream(socket.getInputStream());
32 DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
33
34 outputStream.writeUTF(name);
35 outputStream.writeUTF(password);
36 outputStream.writeUTF(judge);
37
38 String read = inputStream.readUTF();
39
40 //登录是一次性的,所以要及时关闭socket
41 outputStream.close();
42 inputStream.close();
43 socket.close();
44 return read;
45 }
46 }
1 public class Registered_View extends JDialog{
2 // DataJudge dataJudge = new DataJudge();
3 private JTextField textField_1;
4 private JTextField textField;
5 JLabel lblNewLabel_2;
6 private final Action action = new SwingAction();
7
8 public Registered_View(JFrame frame) {
9 super(frame, "", true); //使注册对话框显示在主面板之上。
10 .........
11 .........
12 .........
13 .........
14 }
15
16 private class SwingAction extends AbstractAction {
17 public SwingAction() {
18 putValue(NAME, "注册");
19 putValue(SHORT_DESCRIPTION, "点击按钮进行注册");
20 }
21 public void actionPerformed(ActionEvent e) {
22 String b=null; //用于接收服务端返回的注册信息字符串
23 String name = textField.getText();
24 String password = textField_1.getText();
25 try {
26 b = DataJudge.Judge(6567, name, password, "registered");
27 } catch (IOException e1) {
28 // TODO Auto-generated catch block
29 e1.printStackTrace();
30 }
31
32 lblNewLabel_2.setText(b);
33 }
34 }
1 public static void SendInfo(String rece, String AllName, String num) throws IOException {
2 DataOutputStream outputStream = null;
3 for (Socket Ssocket : Server.socketList) {
4 outputStream = new DataOutputStream(Ssocket.getOutputStream());
5 outputStream.writeUTF(num);
6 outputStream.writeUTF(AllName);
7 outputStream.writeUTF(rece);
8 outputStream.flush();
9 }
10 }
1 面板关闭事件监听
2
3 @Override
4 public void windowClosing(WindowEvent arg0) {
5 try {
6 chat_Client.send("bye");
7 File_O.file_O.readbye("bye");
8 } catch (IOException e) {
9 // TODO Auto-generated catch block
10 e.printStackTrace();
11 }
12 }
1 退出按钮事件监听
2
3 private class SwingAction extends AbstractAction {
4 public SwingAction() {
5 putValue(NAME, "退出");
6 putValue(SHORT_DESCRIPTION, "关闭程序");
7 }
8 public void actionPerformed(ActionEvent e) {
9 int result=optionPane.showConfirmDialog(contentPane, "是否关闭退出", "退出提醒", JOptionPane.YES_NO_OPTION);
10 if(result==JOptionPane.YES_OPTION) {
11 try {
12 chat_Client.send("bye");
13 File_O.file_O.readbye("bye");
14 System.exit(EXIT_ON_CLOSE); //static void exit?(int status) 终止当前正在运行的Java虚拟机。即终止当前程序,关闭窗口。
15 } catch (IOException e1) {
16 e1.printStackTrace();
17 }
18 }
19 }
20 }
1 客户端send方法,发送完bye字符后,关闭socket
2
3 //send()方法,发送消息给服务器。 “发送”button 按钮点击事件,调用此方法
4 public void send(String send) throws IOException {
5 DataOutputStream stream = new DataOutputStream(socket.getOutputStream());
6 stream.writeUTF(Login_View.AllName);
7 stream.writeUTF(send);
8
9 if(send.equals("bye")) {
10 stream.flush();
11 socket.close();
12 }
13 }
1 服务端读取到bye字符时,移除相应socket对象,退出while循环
2
3 if (rece.equals("bye")) {
4 judg = false;
5 Server.socketList.remove(socket);
6 Server_IO.SendInfo("", "", "" + Server.socketList.size());
7 /*
8 * for (Socket Ssocket:Server.socketList) { DataOutputStream outputStream = new
9 * DataOutputStream(socket.getOutputStream()); outputStream = new
10 * DataOutputStream(Ssocket.getOutputStream());
11 * outputStream.writeUTF(""+Server.socketList.size());
12 * outputStream.writeUTF(""); outputStream.writeUTF("");
13 * System.out.println("8888888888888888"); outputStream.flush(); }
14 */
15 break;
16 }
1 while((len=input.read(read,0,read.length))>0) {
2 for(Socket soc:File.socketList_IO) {
3 if(soc != socket)
4 {
5 output = new DataOutputStream(soc.getOutputStream());
6 output.writeUTF(name);
7 output.write(read,0,len);
8 output.flush();
9 // System.out.println("开始向客户机转发");
10 }
11 }
12 // System.out.println("执行");
13 // System.out.println(len);
14 }
while((len=input.read(read,0,read.length))>0),无法退出,从而无法进行下一次读取转发。也无法使用len=-1进行中断break;
修改如下: 1 int len=0;
2 while(true) {
3 len=0;
4 if(input.available()!=0)
5 len=input.read(read,0,read.length);
6 if(len==0) break;
7 for(Socket soc:File.socketlist_file) {
8 if(soc != socket)
9 {
10 output = new DataOutputStream(soc.getOutputStream());
11 output.writeUTF(name);
12 output.write(read,0,len);
13 // output.flush();
14 // System.out.println("开始向客户机转发");
15 }
16 // System.out.println("一次转发"+File.socketlist_file.size());
17 }
18 }
文章标题:java socket实现服务端,客户端简单网络通信。Chat
文章链接:http://soscw.com/index.php/essay/93961.html