发表于: 2018-03-07 22:23:22
1 554
今天完成的事情:(一定要写非常细致的内容,比如说学会了盒子模型,了解了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
评论