实验要求:基于图形界面的局域网点对点打字通信程序
设计思路:
1. 点对点通信应该是一个客户机和一个服务器的通信即客户端和服务器都是单线程
2. 通信肯定要实现多线程即接收和发送信息,这里按照老师给的基于控制台的局域网点对点打字通信程序稍加改动:客户端和服务器实现Runnable接口。重写的run方法作为接收线程体(不再是发送线程体),发送线程体通过main函数实现即创建一个图形界面后在信息输入框里添加发送Enter键按下事件即可达到发送线程体效果。
3. 数据输入方式选择Scanner,输出方式选择PrintWriter比较方便操作。为防止中文乱码Scanner在构造时默认系统编码(我的为utf-8), PrintWriter是在PrintWriter(String fileName, String csn)选择这个构造器时才会指定字符编码,所以用PrintWriter(OutputStream out, boolean autoFlush)应该是默认系统编码,再指定自动执行刷新即可完成通信。
4. 将数据显示在Swing界面上即可完成任务。
实验总结:
实验代码:
package com;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
/**
* 基于图形界面的局域网点对点打字通信程序
1. 统一图形界面实现拨号连接;发送;接收
2. 同一界面下显示发送和连接
3. 在局域网实测
4. 中文不能有乱码
5. 连接超时,断开连接等应有显示提示
* @author 唐树成
*
*/
public class Server22 implements Runnable {
ServerSocket server;
Socket client;
Scanner in;//文本扫描器输入
PrintWriter out;//打印字符输出流比较方便
JFrame frame;//服务器图形界面
JTextField textField;//信息输入框
JTextArea messageArea;//信息接收区域
//主函数入口
public static void main(String[] args) throws UnknownHostException {
new Thread(new Server22(6666)).start();
}
//初始化窗体
public Server22(int port) {
init(port);
}
//窗体初始化内容
public void init(int port) {
//初始化服务器地址
try {
server = new ServerSocket(port);
server.setSoTimeout(10000); //10秒超时
} catch (IOException e) {
e.printStackTrace();
}
//初始化窗体和窗体内组件
textField = new JTextField(50);
messageArea = new JTextArea(16, 50);
messageArea.setText("等待客户端10秒连接。。。\n");
messageArea.setEditable(false);
frame = new JFrame("服务器");
frame.getContentPane().add(textField, BorderLayout.SOUTH);
frame.getContentPane().add(new JScrollPane(messageArea), BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
//添加监听事件
myEvent();
}
//事件监听
public void myEvent(){
//发送信息事件
textField.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ENTER){
messageArea.append("服务器:"+textField.getText() + "\n");
out.println("服务器:"+textField.getText());
textField.setText("");
}
}
});
//关闭窗体事件默认退出程序
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e){
if(null!=out) {
out.println("@服务器关闭!");
}
System.exit(0);
}
});
}
//重写run方法
public void run() {//接收线程体
try {
client = server.accept();
in = new Scanner(client.getInputStream()/*,"utf-8"*/);//默认系统字符集utf-8
out = new PrintWriter(client.getOutputStream(), true);
while (in.hasNextLine()) {
String line = in.nextLine();
messageArea.append(line + "\n");
}
if(null!=in) {
in.close();
}
if(null!=out) {
out.close();
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
JOptionPane.showMessageDialog(frame,"客户端连接超时!");
textField.setEditable(false);
}
}
}
package com;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
/**
* 基于图形界面的局域网点对点打字通信程序
1. 统一图形界面实现拨号连接;发送;接收
2. 同一界面下显示发送和连接
3. 在局域网实测
4. 中文不能有乱码
5. 连接超时,断开连接等应有显示提示
* @author 唐树成
*
*/
public class Client11 implements Runnable {
Socket client;
String serverAddress;//服务器地址
Scanner in;//文本扫描器输入
PrintWriter out;//打印字符输出流比较方便
JFrame frame;//客户端图形界面
JTextField textField;//信息输入框
JTextArea messageArea;//信息接收区域
//主函数入口
public static void main(String[] args) throws UnknownHostException {
//服务器地址(这里服务器和客户端在同一电脑上)
String serverAddress = InetAddress.getLocalHost().getHostAddress();
new Thread(new Client11(serverAddress)).start();
}
//初始化窗体
public Client11(String serverAddress) {
init(serverAddress);
}
//窗体初始化内容
public void init(String serverAddress) {
//初始化服务器地址
this.serverAddress = serverAddress;
//初始化窗体和窗体内组件
textField = new JTextField(50);
messageArea = new JTextArea(16, 50);
messageArea.setEditable(false);
frame = new JFrame("客户端");
frame.getContentPane().add(textField, BorderLayout.SOUTH);
frame.getContentPane().add(new JScrollPane(messageArea), BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
//添加监听事件
myEvent();
}
//事件监听
public void myEvent(){
textField.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ENTER){
messageArea.append("客户端:"+textField.getText() + "\n");
out.println("客户端:"+textField.getText());
textField.setText("");
}
}
});
//关闭窗体事件默认退出程序
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e){
if(null!=out) {
out.println("客户端断开连接");
}
System.exit(0);
}
});
}
//重写run方法
public void run() {//接收线程体
try {
client = new Socket(serverAddress, 6666);
messageArea.setText("连接服务器成功!\n");
in = new Scanner(client.getInputStream()/*,"utf-8"*/);//默认系统字符集utf-8
out = new PrintWriter(client.getOutputStream(), true);
out.println("客户端连接成功!");
while (in.hasNextLine()) {
String line = in.nextLine();
if(line.startsWith("@服务器关闭!")) {
textField.setEditable(false);
messageArea.append(line.substring(1) + "\n");
}else {
messageArea.append(line + "\n");
}
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
messageArea.append("连接服务器失败!\n");
textField.setEditable(false);
}
}
}
附基于控制台的程序代码:
package ppt;
import java.io.*;
import java.net.*;
public class Server1 implements Runnable {
ServerSocket server;
Socket client;
Thread send;
BufferedReader br;
BufferedOutputStream bos;
public void ServerStart() {
try {
server=new ServerSocket(5678);
System.out.println ("本机端口号:"+server.getLocalPort());
server.setSoTimeout(10000*6); //10秒超时
client=server.accept();
System.out.println("已建立连接!");
br=new BufferedReader(new InputStreamReader(client.getInputStream()));
bos=new BufferedOutputStream(client.getOutputStream());
send=new Thread(this);
send.start();
//以下为接收
String str_in;
while((str_in=br.readLine())!=null) {
System.out.println(str_in);
if(str_in.equals("bye")) break;
}
send.interrupt(); //中止发送线程
br.close();
server.close();
bos.close();
client.close();
System.exit(0);
}catch(Exception e) {
System.out.println(e);
}
}
public static void main(String args[]) {
Server1 s=new Server1();
s.ServerStart();
}
public void run() {//发送线程体
try {
int ch;
while((ch=System.in.read())!=-1) {
bos.write(ch);
if(ch=='\n')
bos.flush();
}
} catch(Exception e) {
System.out.println(e);
}
}
}
package ppt;
import java.io.*;
import java.net.*;
public class Client1 implements Runnable {
Socket client;
Thread send;
BufferedReader br;
BufferedOutputStream bos;
public void ClientStart() {
try {
client=new Socket("127.0.0.1",5678);
System.out.println("已建立连接!");
br=new BufferedReader(new InputStreamReader(client.getInputStream()));
bos=new BufferedOutputStream(client.getOutputStream());
send=new Thread(this);
send.start();
//以下为接收
String str_in;
while((str_in=br.readLine())!=null) {
System.out.println(str_in);
if(str_in.equals("bye"))
break;
}
send.interrupt();//中止发送线程
br.close(); bos.close();
client.close();
System.exit(0);
} catch(Exception e) {
System.out.println(e);
}
} //end of ClientStart
public static void main(String args[]) {
Client1 c=new Client1();
c.ClientStart();
}
public void run() {//发送线程体
try {
int ch;
while((ch=System.in.read())!=-1) {
bos.write(ch);
if(ch=='\n')
bos.flush();
}
}catch(Exception e) {
System.out.println(e);
}
} //end of run
} // end of Client1
由此可见该程序只能是单客户端聊天程序。
6. 实验结果:
不启动服务器启动客户端
启动服务器不启动客户端
正常启动后服务器关闭: