《互联网程序设计》 -- 第2周网络对话程序的设计
经历了上一周的学习java,发现自己就是一个five,很多都忘了,还有很多底层也是不会的。很烦。不过还是一点一点地去学一下。来到第二周的互联网程序设计课,这周的任务就是设计一个网络对话程序。
一、总览
就是说通过窗体程序登录到客户端,然后向服务器发送消息(字符串),并能读取字符串返回的消息。
二、TCPServer,服务器的建立
这个还没有看懂下次说,
三、TCPClient,客户端
1、连接对方,先向服务器发起三次握手。
socket = new Socket(host,port); //向服务进程发起TCP三次握手连接
然后获取字节流,(输入和输出)Socket连接成功后,通过调用socket.getXXXXXStream( )方法,可获得字节输出流和字节输入流,输出流用于发送信息,输入流用于接收信息。并可通过以下组合方式封装为输入输出的字符流:
new PrintWriter( // 设置最后一个参数为true,表示自动flush数据 new OutputStreamWriter(//设置utf-8编码 outputStream, "utf-8"), true); new BufferedReader( new InputStreamReader(inputStream, "utf-8"));
这里采用自动flush的方法,如果没有flush则会在缓存区一直出不来,阻塞运行。
2、发送信息给服务器
public void send(String msg) { //输出字符流,由Socket调用系统底层函数,经网卡发送字节流 pw.println(msg); }
3、服务器接收信息
public String receive() { String msg = null; try { //从网络输入字符流中读信息,每次只能接受一行信息 //如果不够一行(无行结束符),则该语句阻塞, // 直到条件满足,程序才往下运行 msg = br.readLine(); } catch (IOException e) { e.printStackTrace(); } return msg; }
4、关闭网络连接
public void close() { try { if (socket != null) { //关闭socket连接及相关的输入输出流,实现四次握手断开,如图2.3所示 socket.close(); } } catch (IOException e) { e.printStackTrace(); } }
四、TCPClientFX,窗体的构建
这个大体上和上一周的simplefx差不多,我就略说了。不过有些是需要注意的点。
1 public void start(Stage primaryStage) { 2 taDisplay.setEditable(false); 3 btnUnConnect.setDisable(true); 4 btnSend.setDisable(true); 5 btnUnConnect.setStyle("-fx-color: RED"); 6 btnExit.setStyle("-fx-color: RED"); 7 BorderPane mainPane = new BorderPane(); 8 9 mainPane.setCenter(getVBox()); 10 mainPane.setBottom(getHBoxBottom()); 11 mainPane.setTop(getHBoxTop()); 12 13 14 15 //这里是按钮的控制: 16 btnConnect.setOnAction(event -> { 17 String ip = tfIP.getText().trim(); 18 String port = tfPort.getText().trim(); 19 20 try { 21 //tcpClient不是局部变量,是本程序定义的一个TCPClient类型的成员变量 22 tcpClient = new TCPClient(ip,port); 23 //成功连接服务器,接收服务器发来的第一条欢迎信息 24 String firstMsg = tcpClient.receive(); 25 taDisplay.appendText(firstMsg + "\n"); 26 27 btnConnect.setDisable(true);//连接服务器之后不能再次连接 28 btnSend.setDisable(false);//连接服务器成功之后才可以发送信息 29 btnUnConnect.setDisable(false);//可以启用断开连接按钮 30 31 } catch (Exception e) { 32 taDisplay.appendText("服务器连接失败!" + e.getMessage() + "\n"); 33 } 34 }); 35 36 37 38 //退出按钮的设置 39 btnExit.setOnAction(event -> { 40 if(tcpClient != null){ 41 //向服务器发送关闭连接的约定信息 42 taDisplay.appendText("bye" + "\n"); 43 // TimeUnit.SECONDS.sleep(2); 44 tcpClient.send("bye"); 45 tcpClient.close(); 46 } 47 System.exit(0); 48 }); 49 50 btnUnConnect.setOnAction(event -> { 51 if(tcpClient != null){ 52 //向服务器发送关闭连接的约定信息 53 taDisplay.appendText("bye,断开连接,拜拜了您嘞!" + "\n"); 54 tcpClient.send("bye"); 55 tcpClient.close(); 56 btnUnConnect.setDisable(true); 57 btnConnect.setDisable(false); 58 btnSend.setDisable(true); 59 } 60 }); 61 62 //点x的设置 63 primaryStage.setOnCloseRequest(event -> { 64 String ip = tfIP.getText().trim(); 65 String port = tfPort.getText().trim(); 66 try { 67 tcpClient = new TCPClient(ip,port); 68 if(tcpClient != null){ 69 //向服务器发送关闭连接的约定信息 70 tcpClient.send("bye"); 71 tcpClient.close(); 72 } 73 System.exit(0); 74 }catch (Exception e){ 75 taDisplay.appendText("退出失败!" + e.getMessage() + "\n"); 76 } 77 }); 78 79 //点x的设置 80 primaryStage.setOnCloseRequest(event -> { 81 String ip = tfIP.getText().trim(); 82 String port = tfPort.getText().trim(); 83 try { 84 TCPClient tcpClient = new TCPClient(ip,port); 85 if(tcpClient != null){ 86 //向服务器发送关闭连接的约定信息 87 tcpClient.send("bye"); 88 tcpClient.close(); 89 } 90 System.exit(0); 91 }catch (Exception e){ 92 taDisplay.appendText("退出失败!" + e.getMessage() + "\n"); 93 } 94 }); 95 96 //发送按钮的设置; 97 btnSend.setOnAction(event -> { 98 String sendMsg = tfSend.getText(); 99 tcpClient.send(sendMsg);//向服务器发送一串字符 100 if (sendMsg.equals("bye")){ 101 btnUnConnect.setDisable(true); 102 btnConnect.setDisable(false); 103 btnSend.setDisable(true); 104 btnSend.setDisable(true); 105 } 106 taDisplay.appendText("客户端发送:" + sendMsg + "\n"); 107 String receiveMsg = tcpClient.receive();//从服务器接收一行字符 108 taDisplay.appendText(receiveMsg + "\n"); 109 tfSend.clear(); 110 }); 111 112 // btnSend.requestFocus(); 113 tfSend.requestFocus();//聚焦一定是在发送框,因为输入信息后焦点就在发送框,而不是按钮或其他 114 tfSend.setOnKeyPressed(event -> { 115 116 if(event.isShiftDown() == true && event.getCode().equals(KeyCode.ENTER )){ 117 String sendMsg = tfSend.getText(); 118 tcpClient.send("echo:" + sendMsg);//向服务器发送一串字符 119 taDisplay.appendText("客户端发送:echo:" + sendMsg + "\n"); 120 String receiveMsg = tcpClient.receive();//从服务器接收一行字符 121 taDisplay.appendText(receiveMsg + "\n"); 122 tfSend.clear(); 123 } 124 else if (event.getCode().equals(KeyCode.ENTER)) { 125 String sendMsg = tfSend.getText(); 126 tcpClient.send(sendMsg);//向服务器发送一串字符 127 taDisplay.appendText("客户端发送:" + sendMsg + "\n"); 128 if (sendMsg.equals("bye")){ 129 btnUnConnect.setDisable(true); 130 btnConnect.setDisable(false); 131 btnSend.setDisable(true); 132 } 133 String receiveMsg = tcpClient.receive();//从服务器接收一行字符 134 taDisplay.appendText(receiveMsg + "\n"); 135 tfSend.clear(); 136 } 137 }); 138 139 Scene scene = new Scene(mainPane,900,500); 140 primaryStage.setTitle("网络通信测试111"); 141 primaryStage.setScene(scene); 142 primaryStage.show(); 143 } 144 145 private VBox getVBox(){ 146 VBox vBox = new VBox(10); 147 vBox.setPadding(new Insets(10,20,10,20)); 148 vBox.getChildren().addAll(new Label("信息显示:") , taDisplay, new Label("信息输入:"), tfSend); 149 VBox.setVgrow(taDisplay, Priority.ALWAYS); 150 151 return vBox; 152 } 153 154 private HBox getHBoxBottom(){ 155 HBox hBox = new HBox(10); 156 hBox.setPadding(new Insets(10,20,10,20)); 157 hBox.setAlignment(Pos.CENTER_RIGHT); 158 hBox.getChildren().addAll(btnSend,btnExit); 159 160 return hBox; 161 } 162 163 private HBox getHBoxTop(){ 164 HBox hBox = new HBox(10); 165 hBox.setPadding(new Insets(10,20,10,20)); 166 hBox.setAlignment(Pos.CENTER); 167 hBox.getChildren().addAll(new Label("IPAdress:") , tfIP, new Label("Interface:"), tfPort, btnConnect,btnUnConnect); 168 169 return hBox; 170 }
btnConnect的按钮是连接服务器,还没懂不谈。其他类似
这里注意的点有,你需要在窗体类TCPClientFX下声明好TCPClient,不然后面的退出按钮的功能你可用不了。
还有的是
在TCPClientFX客户端窗体程序中,连接成功服务器后,如果用户再次点击“连接”按钮,会造成服务器资源浪费,还可能使程序运行不正常,无法正常发送信息;
没有连接服务器时,或者发送bye以后,点击“发送”按钮,控制台也会产生异常;
当已连接上服务器时候,直接就可以在btnConnect连接的代码那里加入这三行代码就可以解决啦。
btnConnect.setDisable(true);//连接服务器之后不能再次连接 btnSend.setDisable(false);//连接服务器成功之后才可以发送信息 btnUnConnect.setDisable(false);//可以启用断开连接按钮
当发送bye的信息给服务器之后,在btnSend按钮的点击动作加入下面的判断代码
if (sendMsg.equals("bye")){ btnUnConnect.setDisable(true); btnConnect.setDisable(false); btnSend.setDisable(true); }
好了,今天就这样理解到这里。
下面是完整程序的代码连接:
https://wws.lanzous.com/iFgtWgmi9mh
认清现实,放弃幻想。
细节决定成败,心态放好,认真学习与工作。