关于java中使用UDP做关于聊天的练习

    真的没发现,写的挺烂的却也有人能看到,我有一种被监督的感觉!

    我想把这个当成自己的笔记,可以随时翻阅!希望学到的东西就是学到了,并记下了,而不是过一段时间就忘记了!

   今天我学到技术点:

  ①Swing布局: BorderLayout、FlowLayout

  ②Swing界面: 本质就是容器,然后我们在这个平面上面铺面板,好比如拼图一样,只是拼图永远是一层,而JFrame这个是可以一层覆盖一层,最后仍然以平面显示给我们看的!

 ③监听器: 

        键盘监听: 只需要实现 KeyListener

        按钮监听: 只需要实现ActionListerner

        具体: ActionListener,KeyListener

        注意点: 因为组件(组成界面的元件)是一个组件,

        而事件由: 事件源、事件种类、监听组成,

        按钮比作事件源,

        那么按钮按下就是事件,按钮释放也是事件

        那么监听器就是ActionListener,监听打了按下采取一个操作,监听到了释放也采取一个操作:

其实这里还涉及到java的设计模式混编,观察者 + 中介者模式==》实现触发器事件(我这仅仅是联想),因为监听在一定程度上我就理解为事件触发器类

④DataGramSocket: 本质就是一个套接字类,并且是final的,用于在至少两个程序进行通信建立连接,就是说客户端与服务端都需要创建这个套接字对象;

DatagramSocket()
DatagramSocket(int port)
DatagramSocket(int port, InetAddress Iaddr)
port:指明通信所用的端口号,如果未指明端口号,则把socket连接到本地主机上一个可用的端口,给出的端口不能冲突
Iaddr:指明一个可用的本地地址


数据包:DataGramPacket:注意: UDP协议本就是不可靠的、无序的、可重复的通信协议,但是通信效率高呀!

DatagramPacket(byte[] buf,int offset,InetAddress addr,int port,int offset);
buf:存放数据报数据
length:指明数据报中数据的长度
addr和port指明目的地址

offset:指明了数据报的位移量


======================================================================================


多线程:


网络编程:


IO流操作:


文件操作:


下面我想贴下模仿的代码:当然是有很大的改进空间的!

package cn.hd.udp;


import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Date;


import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;


/**
 * 界面设计:
 * ①两个文本框
 * ②一个发送按钮
 * @author dudu
 * Swing的界面其实: 容器中不断添加元素
 *
 */
public class UDPServerDemo extends JFrame implements ActionListener,KeyListener{

JTextField txtAddr, txtPort, txtPort2, txtSendInfo;//连接文本
JTextArea  txtReceInfo;//内容区域
JButton btnConn, btnSend;//连接按钮,发送按钮

/**
* 流布局:
*/
public UDPServerDemo() {
super("UDP聊天丑界面");
JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
JLabel lbladdr = new JLabel("IP地址", JLabel.RIGHT);
JLabel lblport = new JLabel("通讯端口", JLabel.RIGHT);
txtAddr = new JTextField("127.0.0.1", 14);
txtPort = new JTextField("8888", 5);
txtPort2 = new JTextField("9999", 5);
btnConn = new JButton("连接");
//加入到panel里
topPanel.add(lbladdr);//先右边标签
topPanel.add(txtAddr);//后左边文本
topPanel.add(lblport);//先右边标签
topPanel.add(txtPort);//后左边文本
topPanel.add(txtPort2);//后左边文本
topPanel.add(btnConn);//加入按钮
//将面板加入到容器中: 边界布局靠北
add(topPanel, BorderLayout.NORTH);
txtReceInfo = new JTextArea();
txtReceInfo.setEditable(false);//设置接受框中内容为只读
JScrollPane spane = new JScrollPane(txtReceInfo);
add(spane);

JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
txtSendInfo = new JTextField(35);
btnSend = new JButton("发送(&S)");
btnSend.setMnemonic('S');//快捷键
bottomPanel.add(txtSendInfo);
bottomPanel.add(btnSend);

add(bottomPanel, BorderLayout.SOUTH);
//为按钮设置监听
btnConn.addActionListener(this);
btnSend.addActionListener(this);
txtSendInfo.addKeyListener(this);
//将发送添加回车键监听
// btnSend.addKeyListener(new KeyListener() {
//
// @Override
// public void keyTyped(KeyEvent e) {
//
// }
//
// @Override
// public void keyReleased(KeyEvent e) {
//
// }
//
// @Override
// public void keyPressed(KeyEvent e) {
// if(e.getKeyChar() == KeyEvent.VK_ENTER) {
// System.out.println("true");
// btnSend.doClick();//触发按钮点击事件==》相当于点击了发送,此时监听器监听到这个行为,就将发送内容
// }
// }
// });

setSize(500, 400);
setVisible(true);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

public static void main(String[] args) {
new UDPServerDemo();
}


@Override
public void actionPerformed(ActionEvent e) {
//点击连接按钮时启动接收线程
if(e.getSource() == btnConn) {
int nport = Integer.parseInt(txtPort.getText().trim());
new ReceiveThread(nport).start();//启动线程
btnConn.setEnabled(false);//设置按钮为不可用状态
// JOptionPane.showMessageDialog(null, "连接成功,开始聊吧!");
txtReceInfo.setText("连接成功,开始聊吧!\n");
}
//发送按钮就是发送线程
if(e.getSource() == btnSend) {
// JOptionPane.showMessageDialog(null, "连接成功,开始发送消息吧!");
//先判断是否创建了连接
if(btnConn.isEnabled()) {
JOptionPane.showMessageDialog(null, "还未连接服务器,请先连接...");
txtSendInfo.setText("");
return;
} else {
//可以开始发送UDP数据
//要发送信息给对方法的ip地址:其实就是本机ip
String addr = txtAddr.getText().trim();
int nport2 = Integer.parseInt(txtPort2.getText().trim());
//获取原来的所有接收框的内容
String str = txtReceInfo.getText();
//获取要发送的内容
String msg = txtSendInfo.getText();
//将其转换成字节数组
byte[] bs = msg.getBytes();
//设置ip对方ip
try {
InetAddress iaddr = InetAddress.getByName(addr);
//创建发送的datagramSocket
DatagramSocket socket = new DatagramSocket();
//打包
/*
* 1:bs:要发送的内容
* 2:开始位置:从哪个位置开始发送
* 3:bs.length:发送的长度
* 4:发送的对方ip地址
* 5:通过哪个端口发送: 这个端口由服务器决定
*/
DatagramPacket p = new DatagramPacket(bs, 0, bs.length, iaddr, nport2);
//发送: 将我的内容发送给别人,同时也发送到我自己的对话框中
socket.send(p);
str += "本机Ip:" + iaddr + ":" + nport2 + " " + new Date().toLocaleString() + "\n" + msg + "\n";
txtReceInfo.setText(str);
txtSendInfo.setText("");
socket.close();
} catch (UnknownHostException ex) {
ex.printStackTrace();
} catch (SocketException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}

/**
* 负责来接收消息
* 接收线程:
* @author dudu
*
*/
class ReceiveThread extends Thread {

String addr;
int port;
DatagramSocket receiveSocket = null;
DatagramPacket receiveData = null;

public ReceiveThread(int port) {
// this.addr = addr;
this.port = port;
try {
//启动socket
// receiveSocket = new DatagramSocket(port);
receiveSocket = new DatagramSocket(port);
} catch (SocketException e) {
e.printStackTrace();
}
}


@Override
public void run() {
//然后这就是一个专门接收信息的线程
byte[] buf = new byte[1000];
while(true) {
//创建一个接收数据的包:一次最多64K,接收后放到字节数组中去
receiveData = new DatagramPacket(buf, buf.length);
try {
//接收对方发送的数据
receiveSocket.receive(receiveData);//等待消息(阻塞状态)反正一直会阻塞在这个地方
//接收到流socket中后需要解析
String str = new String(buf, 0, receiveData.getLength());
//获取接收框中原有的内容
String msg = txtReceInfo.getText();
msg += "对方机Ip:" + receiveData.getAddress() + ":" + receiveData.getPort() + " " +  new Date().toLocaleString() + "\n" +  str + "\n";
//把内容显示到接收框中
txtReceInfo.setText(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}


@Override
public void keyTyped(KeyEvent e) {

}


@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyChar() == KeyEvent.VK_ENTER) {
// System.out.println("true");
btnSend.doClick();//触发按钮点击事件==》相当于点击了发送,此时监听器监听到这个行为,就将发送内容
}
}


@Override
public void keyReleased(KeyEvent e) {

}

}

总结: 其实我就是想记录记录每天学习的东西以及一些心得!

希望能被提出意见!谢谢!




 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值