发表于: 2018-03-07 22:23:22

1 552


今天完成的事情:(一定要写非常细致的内容,比如说学会了盒子模型,了解了Margin) 

卢静他今天小课堂,所以准备了一天,就没法继续搞方案,完善了一下之前做的UDP聊天小程序.并打包成可执行jar包.

对应代码如下:

package com.UDP.socket;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
* @author: Arike
* @program: network
* @description: gui聊天
* @create: 2018/2/24 20:59
*/

public class Demo4_GuiChat extends Frame {

private TextField tf;
   private Button send;
   private Button log;
   private Button clear;
   private Button shake;
   private TextArea sendText;
   private TextArea viewText;
   private DatagramSocket socket;
   private BufferedWriter bw;
   
   public Demo4_GuiChat() throws HeadlessException {
init();//进行初始化
       southPanel();//设置南部panel嵌入
       centerPaner();//中部panel嵌入
       event();//监听加入
       this.setVisible(true);//设置gui可见
   }

/**
    * 初始化方法
    */
   private void init() {
new Receive().start();//开启socket接收线程
       try {
socket = new DatagramSocket(20089);//生成发送socket
           
           bw = new BufferedWriter(new FileWriter("log.txt", true));//关联写出聊天记录文件
       } catch (Exception e) {
e.printStackTrace();
       }
this.setLocation(500, 150);//设置frame位置.
       this.setSize(480, 600);//设置Frame大小
       
   }

/**
    * 设置底部布局
    */
   private void southPanel() {
Panel south = new Panel();//生成底部嵌板
       tf = new TextField(15);//生成一个文本输入框
       tf.setText("192.168.31.");//设置文本输入框默认值
       send = new Button("发送");//生成发送按钮
       log = new Button("记录");//生成记录按钮
       clear = new Button("清屏");//生成清屏按钮
       shake = new Button("震动");//生成震动按钮
       south.add(tf);//将各单位添加到南部布局.
       south.add(send);
       south.add(log);
       south.add(clear);
       south.add(shake);
       this.add(south, BorderLayout.SOUTH);//将南部布局添加到frame的南部
   }

/**
    * 设置中部布局
    */
   private void centerPaner() {
Panel center = new Panel();//生成中部嵌板
       viewText = new TextArea();//生成显示文本区域
       sendText = new TextArea(6, 1);//生成输入文本区域
       
       center.setLayout(new BorderLayout());//将中部嵌板设置为边界布局,默认是流式布局.
       center.add(sendText, BorderLayout.SOUTH);//将发送文本区域添加到中部嵌板的南部.
       center.add(viewText, BorderLayout.CENTER);//将显示文本区域添加到中部嵌板的中部.
       viewText.setEditable(false);//设置显示区域不可写
       viewText.setBackground(Color.WHITE);//设置显示区域背景色为白色
       sendText.setFont(new Font("xxx", Font.PLAIN, 15));//设置文本区域的字体以及样式和大小(都使用的默认,字体名称乱填"xxx"会使用默认字体)
       viewText.setFont(new Font("xxx", Font.PLAIN, 15));
       this.add(center, BorderLayout.CENTER);//将中部布局添加到frame的中部
   }

/**
    * 事件触发管理方法
    */
   private void event() {
this.addWindowListener(new WindowAdapter() {
@Override
           public void windowClosing(WindowEvent e) {
socket.close();
               try {
bw.close();
               } catch (IOException e1) {
e1.printStackTrace();
               }
System.exit(0);
           }
});//为frame "x"赋予关闭功能,并且完成输出流的关闭以及sokect发送口的关闭.
       
       send.addActionListener(new ActionListener() {
@Override
           public void actionPerformed(ActionEvent e) {
try {
send();
               } catch (Exception e1) {
e1.printStackTrace();
               }
}
});//为发送按钮添加动作监听(空格和单击),点击执行发送方法.
       
       sendText.addKeyListener(new KeyAdapter() {
@Override
           public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER /*&& e.isAltDown()*/) {
try {
send();
                   } catch (Exception e1) {
e1.printStackTrace();
                   }
}
}
});//为输入文本框添加按键监听,单击回城执行发送方法.
       
       log.addActionListener(new ActionListener() {
@Override
           public void actionPerformed(ActionEvent e) {
logfile();
           }
});//为记录按钮添加动作监听.
       
       clear.addActionListener(new ActionListener() {
@Override
           public void actionPerformed(ActionEvent e) {
clearScreen();
           }
});
       
       shake.addActionListener(new ActionListener() {
@Override
           public void actionPerformed(ActionEvent e) {
sendShake();
           }
});
   }

/**
    * 震动
    */
   private void shake() {
int x = this.getLocation().x;
       int y = this.getLocation().y;
       
       for (int i = 0; i < 5; i++) {
try {
this.setLocation(x + 20, y + 20);
               Thread.sleep(20);
               this.setLocation(x + 20, y - 20);
               Thread.sleep(20);
               this.setLocation(x - 20, y + 20);
               Thread.sleep(20);
               this.setLocation(x - 20, y - 20);
               Thread.sleep(20);
               this.setLocation(x + 20, y + 20);
               Thread.sleep(20);
               this.setLocation(x + 20, y - 20);
               Thread.sleep(20);
           } catch (InterruptedException e) {
e.printStackTrace();
           }
}

this.setLocation(x, y);
   }

/**
    * 清屏
    */
   private void clearScreen() {
viewText.setText("");
   }

/**
    * 调取文件/服务器中的聊天记录
    */
   private void logfile() {
FileInputStream fis = null;
       try {
fis = new FileInputStream("log.txt");
           ByteArrayOutputStream baos = new ByteArrayOutputStream();//在内存中创建缓冲区
           int len;
           byte[] arr = new byte[8192];
           while ((len = fis.read(arr)) != -1) {
baos.write(arr, 0, len);
           }
String str = baos.toString();
           viewText.setText(str);
           fis.close();
       } catch (Exception e) {
e.printStackTrace();
       }
}

private void sendShake() {
try {
String ip = tf.getText();//获取到南部文本输入框中输入的ip地址
           ip = ip.trim().length() == 0 ? "255.255.255.255" : ip;//这表示群发.
           String time = getCurrentTime();//获取到当前时间
           DatagramPacket packet = new DatagramPacket(new byte[]{1}, 1, InetAddress.getByName(ip), 9999);
           
           socket.send(packet);
           String str = "我向" + (ip.equals("255.255.255.255") ? "所有人" : ip) + "发送了震屏(" + time + ")" + "\r\n" + "\r\n";
           viewText.append(str);
           bw.write(str);
           bw.flush();
       } catch (Exception e) {
e.printStackTrace();
       }

}


/**
    * 发送消息方法
    *
    * @throws Exception
    */
   private void send() throws Exception {
String message1 = sendText.getText();//获取到输入文本区域里面的字符
       String message;//用于接收发送的字符
       String ip = tf.getText();//获取到南部文本输入框中输入的ip地址
       ip = ip.trim().length() == 0 ? "255.255.255.255" : ip;//这表示群发.
       String time = getCurrentTime();//获取到当前时间
       String[] arr = message1.split("\n");//用换行符作为分隔符进行分割输入的字符,因为敲击回城也会被当做一个字符,所以发送的消息应该是回车符之前的字符串,所以需要做这么一个切割.
       if (arr.length == 0) {
message = "";
       } else {
message = arr[0];
       }//这个判断是为了完成对方只输入了一个回城的情况,这种情况分割下来的字符数组长度为0.
       String str = "我对" + (ip.equals("255.255.255.255") ? "所有人" : ip) + "说(" + time + "):" + "\r\n" + message + "\r\n";
       DatagramPacket packet = new DatagramPacket(message.getBytes(), message.getBytes().length, InetAddress.getByName(ip), 20088);//将需要发送的数据打包到packet中等待发送.
       socket.send(packet);//发送消息
       viewText.append(str);//自己的窗口显示发送的数据.
       sendText.setText("");//发送消息后清空文本输入区域.
       bw.write(str);//将消息记录保存到文件中.
       bw.flush();
   }

/**
    * 获取到当前时间
    *
    * @return
    */
   private String getCurrentTime() {
Date date = new Date();
       SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
       return sdf.format(date);
       
   }

/**
    * 接收消息的方法.
    */
   private class Receive extends Thread {
@Override
       public void run() {
try {
DatagramSocket socket = new DatagramSocket(20088);//获取到插座对应货物的端口号
               DatagramPacket packet = new DatagramPacket(new byte[8192], 8192);//设置接收货物的包裹大小.
               while (true) {//进行无限循环接收,只有当程序关闭时才关闭.
                   socket.receive(packet);//接收数据
                   byte[] arr = packet.getData();//将数据存储到字节数组中
                   int len = packet.getLength();//获取到数据的真实长度.
                   String ip = packet.getAddress().getHostAddress();//获取到发送数据的IP地址
                   String myip = InetAddress.getLocalHost().getHostAddress();//获取到自己的IP地址
                   if (ip.equals(myip)) {
continue;
                   }
String time = getCurrentTime();//获取当前时间
                   String message = new String(arr, 0, len);
                   String str = ip + "对我" + "说(" + time + "):" + "\r\n" + message + "\r\n";
                   if (arr[0] == 1 && len == 1) {
shake();
                       String str1 = ip + "向我发送了震屏" + "(" + time + ")" + "\r\n" + "\r\n";
                       viewText.append(str1);
                       bw.write(str1);
                       bw.flush();
                   } else {
viewText.append(str);//将接收到数据添加到文本显示区域.
                       bw.write(str);//将接收到的消息添加到聊天记录.
                       bw.flush();
                   }
}

} catch (Exception e) {
e.printStackTrace();
           }
}
}

public static void main(String[] args) {

new Demo4_GuiChat();
       
   }
}

小程序界面如下:

另外跨平台聊天字符集这个问题有点蛋疼,win的字符集是GBK,Mac的字符集是UTF-8.

所以我搞了2个版本的.. 互通的问题有空了解决..

然后是使用tcp协议的服务端和客户端模式的socket.

服务端

package com.TCP;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
* @author: Arike
* @program: network
* @description: socket服务端
* @create: 2018/3/8 07:34
*/

public class Demo1_Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(20998);//开启固定端口号的服务端,默认以本地ip启动服务
       
       while (true) {//开启一个无限循环
           final Socket socket = serverSocket.accept();//接收客户端的请求.
           new Thread(() -> {//接收到请求之后开启一条线程.
               try {
while (true) {
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));//用于接收客户端的请求.
                       PrintStream pa = new PrintStream(socket.getOutputStream());
                       //用于给客户端发送请求.
                       String str = br.readLine();//读取一条消息记录.
                       
                       str = new StringBuilder(str).reverse().toString();//使用stringBuilder来进行反转
                       pa.println(str);//将反转后的字符串输出给客户端.
//                    socket.close();
                   }

} catch (IOException e) {
e.printStackTrace();
               }
}).start();
       }

}
}

客户端:

package com.TCP;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

/**
* @author: Arike
* @program: network
* @description: socket客户端
* @create: 2018/3/8 07:35
*/

public class Demo1_Client {
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(System.in);//获取到键盘输入
       Socket socket = new Socket("127.0.0.1", 20998);//开启一个固定ip和端口号的连接
       
       BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
       //用于接收服务端发送过来的消息
       PrintStream ps = new PrintStream(socket.getOutputStream());
       //用于向服务端发送消息
       while (true) {
ps.println(sc.nextLine());//向服务端发送消息.
           System.out.println(br.readLine());//接收服务端的消息
       }
}
}

这个的功能就是讲客户端发送的数据到服务端进行反转之后返回,有点类似于RMI,逻辑由服务端来完成,我们测试一下.

明天计划的事情:(一定要写非常细致的内容) 

完成方案设计.
遇到的问题:(遇到什么困难,怎么解决的) 

对io流的知识有点模糊了,感觉基础的知识得随时温故.
收获:(通过今天的学习,学到了什么知识)

了解到了UDP协议和TCP协议的区别

一个像是发短信,无状态.   UDP

一个像是打电话,都必须在线状态.  TCP




返回列表 返回列表
评论

    分享到