/*
* TalkProgram.java
*
* Created on 2007年7月11日, 上午11:40
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
/**
*
* @author Wayne
*/
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import java.net.*;
import javax.swing.*;
import java.util.zip.*;
/*--------------------------------------定义常用变量接口---------------------------------------*/
interface MyValue {
int WEIGHT1 = 20;
int WEIGHT2 = 10;
int WEIGHT3 = 30;
int HEIGHT1 = 30;
int LOCATION = 200;
int ININWEIGHT = 200;
String s1 = "发送";
String s2 = "消息:";
String s3 = "Wayne";
String s4 = "文件";
String s5 = "保存聊天信息";
String s6= "读取聊天信息";
String s7="对方IP";
String s8="帮助";
String s9="帮助文档";
String s10="编辑";
String s11="删除记录";
String s12="查找记录";
String s13="传文件";
String s14="关闭";
String s15="Connect";
String user="对方";
String s16="Port";
String s17="共可输入20个字符";
String ip="127.0.0.1";
int INITHEIGHT = 200;
}
/*========================================核心程序================================================*/
public class TalkProgram extends Frame implements MyValue{
private Button b1 = null;
private Button b2 = null;
private Button b3 = null;
private Button b4 = null;
private TextField t1 = null;
private TextField t2 = null;
private TextField t3 = null;
private TextArea ta1 = null;
private Panel p1 = null;
private Panel p2 = null;
private Label l1 = null;
private Label l2 = null;
private Label l3 = null;
private Label l4 = null;
public DatagramSocket socket=null;//声明datagramsocket套接字,随机绑定一个有效的端口;
int SERVERPORT=8080;//默认端口为:8080
public static String serverIP="127.0.0.1";//默认为本机
public static int PORT;//对话框输入对方的服务器的端口号
public String port1;//自己方服务器的端口
public TalkProgram()
{//构造函数
super(s3);
/*------------------------ 初始化所有需要的部件------------------------------------*/
t1 = new TextField("", WEIGHT1);
t2 = new TextField("", WEIGHT3);
t1.addKeyListener(new stringlLeft());
t3 = new TextField("", WEIGHT2/2);
ta1 = new TextArea(WEIGHT2, HEIGHT1);
b1 = new Button(s1);
b2=new Button(s13);
b2.addActionListener(new send());
b3=new Button(s14);
b4=new Button(s15);
b4.addActionListener(new connect());
p1 = new Panel();
p2 = new Panel();
l1 = new Label(s2);
l2 = new Label(s7);
l3 = new Label(s16);
l4 = new Label(s17);
p1.setLayout(new FlowLayout());
p1.add(l1);
p1.add(t1);
p1.add(l4);
p1.add(b1);
b1.addActionListener(new SendMessage ());
p1.add(b2);
p1.add(b3);
b3.addActionListener(new closeConnect());
p2.setLayout(new FlowLayout());
p2.add(l3);
p2.add(t3);
p2.add(l2);
p2.add(t2);
p2.add(b4);
/*------------------------------下面是关于菜单部分-------------------------------------*/
MenuBar mb = new MenuBar();
Menu m1 = new Menu(s4);
Menu m2= new Menu(s10);
Menu m3 = new Menu(s8);
MenuItem mi1 = new MenuItem(s5,new MenuShortcut(KeyEvent.VK_S));
MenuItem mi2 = new MenuItem(s6,new MenuShortcut(KeyEvent.VK_O));
MenuItem mi3 = new MenuItem(s11,new MenuShortcut(KeyEvent.VK_X));
MenuItem mi4 = new MenuItem(s9,new MenuShortcut(KeyEvent.VK_H));
MenuItem mi5 = new MenuItem(s12,new MenuShortcut(KeyEvent.VK_F));
m1.add(mi1);
m1.addSeparator();
m1.add(mi2);
m2.add(mi3);
m2.addSeparator();
m2.add(mi5);
m3.add(mi4);
mi1.addActionListener(new SaveMenuItem());
mi2.addActionListener(new ReadMenuItem());
mi3.addActionListener(new deleteContent());
mi4.addActionListener(new showHelp());
mb.add(m1);
mb.add(m2);
mb.add(m3);
port1 = JOptionPane.showInputDialog(null,"服务器端口","端口号:" + "",JOptionPane.QUESTION_MESSAGE);
System.out.println("server port is "+port1);
SERVERPORT=getPort(port1);
System.out.println("server port is "+SERVERPORT);
this.setMenuBar(mb);
/* -------------------------组合各个部件和相互的关系----------------------------*/
this.setLayout(new BorderLayout(5, 5));
this.add(p2,BorderLayout.NORTH);
this.add(ta1, BorderLayout.CENTER);
this.add(p1, BorderLayout.SOUTH);
this.pack();//简单整理一下部件布局
this.setLocation(LOCATION, LOCATION);
this.setVisible(true);
/*----------------------------关闭窗口------------------------------------------------*/
this.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
}
);
/* -------------------------------------------启动server监听端口是否有人连接----------- -----------------------------------------*/
receiveMessage waitMessage=new receiveMessage();//启动server线程监听是否有人连接
Thread td1=new Thread(waitMessage);
td1.start();
receiveFile waitFile=new receiveFile();
Thread td2=new Thread(waitFile);
td2.start();
}//构造函数结束
public String getIP()
{
String ip=t2.getText();
return ip;
}
public int getPort(String s)
{
if(s!="")
{
int s1=Integer.parseInt(s);
return s1;
}else return SERVERPORT;
}
/*-----------------------------delete chat content-----------------------------------------------------*/
class deleteContent implements ActionListener{
public void actionPerformed(ActionEvent e){
ta1.setText(null);
}
}
/*--------------------------------------显示帮助文档--------------------------------------------------*/
class showHelp implements ActionListener{
public void actionPerformed(ActionEvent e){
JOptionPane.showMessageDialog(null,"该作品制作人:王宁/n学号:05301052/n/n感谢大家对本产品的支持!");
}
}
/*-----------------save chat content-----------------------------*/
class SaveMenuItem implements ActionListener{//save chat message
public void actionPerformed(ActionEvent e)//保存信息
{
FileOutputStream out;
PrintStream p; //声明一个Print Stream流
try {
out = new FileOutputStream("chatlog.txt",true);
p = new PrintStream( out );
p.println (ta1.getText());//方法println(),它将一个字符串发送给输出流。
p.close();
} catch (Exception e1) {
System.err.println ("Error writing to file");
}
}
}
/*-------------------read chat content--------------------------*/
class ReadMenuItem implements ActionListener{//read chat message
public void actionPerformed(ActionEvent e){//读取信息
//定义一个byte数组用于接收从文件中读出的字节,注意它的长度为1024
byte[] buff = new byte[1024];
int n;
FileInputStream fis = null;
// 生成对象infile 准备读取文件
try
{
File f=new File("chatlog.txt");
fis=new FileInputStream(f);
// 从文件读取数据
while((n = fis.read(buff,0,1024))!=-1)
{
String s=new String(buff,0,n);
ta1.append(s);
fis.close();
}
}
catch (FileNotFoundException e1)
{
System.out.println("没有找到文件");
System.exit(1);
}
catch (IOException e2)
{
System.out.println("");
}
//清理
finally
{
try
{
fis.close();
}
catch (IOException e3)
{
System.out.println("文件错误");
System.exit(1);
}
}
}
}
/*------------------------------------connect to server--------------------------------------------------*/
class connect implements ActionListener
{
public void actionPerformed(ActionEvent e)
{//发送消息的实现
try {
serverIP=getIP();
PORT=getPort(t3.getText());
socket = new DatagramSocket();//建立对象
System.out.println("connect successfully");
}
catch (SocketException e1) {
System.err.println("Can't open socket");
System.exit(1);
}
}
}
/*--------------------------------------client:send message --------------------------------------*/
class SendMessage extends connect implements ActionListener
{
//发送消息的实现
public void actionPerformed(ActionEvent e){
try {
//构造数据报包,用来将包发送到指定主机上的指定端口号。
System.out.println("Ip="+serverIP);
System.out.println("Port="+PORT);
DatagramPacket echo = Dgram.toDatagram(t1.getText(), InetAddress.getByName(serverIP), PORT);
System.out.println("send message is used!");
socket.send(echo);//传送数据包
String s = Dgram.toString(echo);
//时间的显示
Calendar calendar=Calendar.getInstance();
int hour=calendar.get(Calendar.HOUR_OF_DAY);
int minute=calendar.get(Calendar.MINUTE);
int second=calendar.get(Calendar.SECOND);
ta1.append("自己:"+hour+"时"+minute+"分"+second+"秒:"+"/n"+s+"/n"+"/n");
//System.err.println("Send OK");
} catch (IOException e1) {
System.err.println("Communication error");
e1.printStackTrace();
}
t1.setText(null);
}
}
/*---------------------------------------close connection------------------------------------------*/
class closeConnect extends connect implements ActionListener//close connect
{
public void actionPerformed(ActionEvent e)
{
ta1.append("connect is closed");
socket.close();
}
}
/*------------------------------------server:receive message ----------------------------------------*/
class receiveMessage implements Runnable {
private byte[] buf = new byte[1000];//存放接受信息数组
private DatagramPacket dp = new DatagramPacket(buf, buf.length);// 构造 DatagramPacket,用来接收长度为 length 的数据包。
private DatagramSocket socket;//DatagramSocket套接字
String date;
public void run() {//有机会在虚拟cpu上执行的代码
try {
socket = new DatagramSocket(SERVERPORT);
System.out.println("Server started");
while (true) {
socket.receive(dp);//阻塞等待连接,和client建立数据链路
String rcvd = Dgram.toString(dp);//将接收的包转化为字符串
//时间的显示
Calendar calendar=Calendar.getInstance();
int hour=calendar.get(Calendar.HOUR_OF_DAY);
int minute=calendar.get(Calendar.MINUTE);
int second=calendar.get(Calendar.SECOND);
System.out.println("data=" + rcvd );
ta1.append(user+":"+hour+"时"+minute+"分"+second+"秒:"+"/n"+rcvd+"/n"+"/n");
}
} catch (SocketException e) {//异常处理
System.err.println("Can't open socket");
System.exit(1);
} catch (IOException e) {
System.err.println("Communication error");
e.printStackTrace();
}
}
}
/*--------------------------------------server:receive file---------------------------------------*/
class receiveFile implements Runnable {
//static final int INPORT1 = 8888;//端口号
public void run() {
try{
ServerSocket server;
server = new ServerSocket(SERVERPORT);
//创建绑定到特定端口的服务器套接字。
Socket sock;//创建一个Socket对象。服务器端便可以利用这个Socket对象与客户进行通讯。
while(true){
sock = server.accept();//侦听并接受到此套接字的连接
InetAddress addr = sock.getInetAddress();//返回套接字连接的地址。
System.out.println(addr.getHostAddress());
//使用指定的基础 InputStream 创建一个 DataInputStream。
DataInputStream infilename =
new DataInputStream(sock.getInputStream());
//从流infilename中读取用 UTF-8 修改版格式编码的 Unicode 字符格式的字符串;然后以 String 形式返回此字符串。
String filename = new String(infilename.readUTF());
System.out.println("filename="+filename);
ta1.append("File"+filename+" is from"+addr.getHostAddress()+"/n");
File file = new File("C:"+filename);//创建一个File实例
//当且仅当不存在具有此抽象路径名指定的名称的文件时,原子地创建由此抽象路径名指定的一个新的空文件。
file.createNewFile();
//创建从中读取和向其中写入(可选)的随机存取文件流,该文件由 File 参数指定。
RandomAccessFile raf = new RandomAccessFile(file,"rw");
InputStream netIn= sock.getInputStream();//返回此套接字的输入流。
//BufferedInputStream(netIn),创建 BufferedInputStream 并保存其参数,以便将来使用。
DataInputStream in =
new DataInputStream(new BufferedInputStream(netIn));
byte[] buf = new byte[2048];
//从所包含的输入流中读取一定数量的字节,并将它们存储到缓冲区数组 buf 中。
int num = in.read(buf);
if(num!=(-1))ta1.append("File is sending.../n");
while(num != (-1))//是否读完所有数据
{
//将 num 个字节从指定字节数组写入到此文件,并从偏移量 0处开始。
raf.write(buf,0,num);//将数据写往文件
//尝试跳过输入的 num 个字节以丢弃跳过的字节。
raf.skipBytes(num);//顺序写文件字节
num=in.read(buf);//继续读取文件
}
if(num==(-1))ta1.append("The file has been saved to C disk"+"/n");
in.close();
raf.close();
}
}catch (Exception e){
System.out.println("receive error!");
}
}
}
/*-------------------------------------compress files-----------------------------------------*/
/*-------------------------------client:send file--------------------------------------------*/
class sendFile implements Runnable
{
public void run()
{
JFileChooser fc = new JFileChooser();
int return_value = fc.showOpenDialog(b2);
if(return_value == JFileChooser.APPROVE_OPTION)
{
File file = fc.getSelectedFile();
try{
PORT=getPort(t3.getText());
serverIP=getIP();
//通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。
FileInputStream fos = new FileInputStream(file);
Socket socket = new Socket(serverIP,PORT);//创建连接到指定服务器的套接字
socket.setSoTimeout(20);
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
out.writeUTF(file.getName());//以与机器无关方式使用 UTF-8 修改版编码将一个字符串写入基础输出流。
ta1.append("File "+file.getName()+" begins to send!/n");
OutputStream netOut = socket.getOutputStream();
//BufferedOutputStream,该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入基础输出流中,而不必为每次字节写入调用基础系统。
OutputStream doc = new DataOutputStream(new BufferedOutputStream(netOut));
byte[] buf = new byte[2048];
//从此输入流中将最多 buf.length 个字节的数据读入一个字节数组中。
int num = fos.read(buf);
if(num != (-1))ta1.append("File is sending.../n");
while(num != (-1))//是否读完文件
{
doc.write(buf,0,num);//将指定字节数组中从偏移量0 开始的 num 个字节写入基础输出流。
doc.flush();//清空此数据输出流。
num=fos.read(buf);//继续从文件中读取数据
}
if(num == (-1))ta1.append("The file sending is over./n");
fos.close();
netOut.close();
Thread.sleep(500);
}
catch(Exception ex)
{
}
}
}
}
class send implements ActionListener
{
public void actionPerformed(ActionEvent e){
try{
sendFile send=new sendFile();//启动server线程监听是否有人连接
Thread td=new Thread(send);
td.start();
}catch(Exception e1)
{
System.out.println(" sendfile thread is error!");
}
}
}
/*------------------------------------------------------------------------------------------------------*/
class stringlLeft implements KeyListener
{
String str,str1,str2;
public void keyReleased(KeyEvent e)
{
int n=20-t1.getText().length();
if(n>=0)
{
str=String.valueOf(n);
l4.setText("还可输入"+str+"个字符");
str1=t1.getText();
System.out.println(str1);
}
else
{
t1.setText(str1);
}
}
public void keyPressed(KeyEvent e1)
{
}
public void keyTyped(KeyEvent e){
}
}
/*------------------------------Creates a new instance of TalkProgram ---------------------------------*/
public static void main(String args[]) {
new TalkProgram();
}
}
/*
* Dgram.java
*
* Created on 2007年7月13日, 下午3:05
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
/**
*
* @author Administrator
*/
import java.net.*;
public class Dgram {
public static DatagramPacket toDatagram(String s, InetAddress destIA,
int destPort) {
byte buf[]=s.trim().getBytes();
//byte[] buf = new byte[s.length()];
//s.getBytes(0, s.length(), buf, 0);
//构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
return new DatagramPacket(buf, buf.length, destIA, destPort);
}
public static String toString(DatagramPacket p) {
return new String(p.getData(), 0, p.getLength());}
}