、
实现一个一对多的聊天程序
一、实验题目
实现一个一对多的聊天程序。其基本过程如下:服务器首先启动,创建套接字后等待客户的连接;客户启动以后,创建套接字,然后和服务器建立连接;连接建立后,客户机和服务器可以通过建立的套接字连接进行通信。服务器和客户端可以是一台电脑上的两个进程,也可以分别部署在两台电脑上。
二、原理概述
TCP是一种可靠的、基于连接的网络传输协议,当两个网络进程准备进行通信时,都必须首先建立各自的一个套接口,其中服务器建立套接口后,侦听来自网络的客户连接请求,客户通过套接口,指定服务器的IP 地址和端口号,便可与服务器通信。
聊天程序采用的是C/S通信模式,即客户/服务模式,它把一个应用划分成功能不同的两个部分,分别在不同的计算机上运行,其中一个为服务端程序,用来响应和提供固定的服务,一个为客户端程序,用来向服务端提出请求和要求某种服务。在数量关系上,通常有一对多的(即一个服务端程序和一个客户端程序之间通信)。
客户机/服务器模式在操作过程中采取的是主动请示方式:
首先服务器方要先启动,并根据请示提供相应服务:
(1)打开一通信通道并告知本地主机,它愿意在某一个公认地址上接收客户请求。
(2)等待客户请求到达该端口。
(3)接收到重复服务请求,处理该请求并发送应答信号。
(4)返回第二步,等待另一客户请求
(5)关闭服务器。
客户方:
(1)打开一通信通道,并连接到服务器所在主机的特定端口。
(2)向服务器发送服务请求报文,等待并接收应答;继续提出请求……
(3)请求结束后关闭通信通道并终止。
图1基于连接的服务者、客户服务流程图
三、设计方案
服务程序运行在服务器主机的某个端口上,一旦启动服务,它将在这个端口上倾听,等待客户程序发来的请求。服务器的套接口用服务器套接口类(ServerSocket)来建立。
1、根据程序设计题目时首先明确程序的目的以及任务
2、利用JAVA语言编写程序,使用套接字来完成测试功能。
3、程序在Eclipcse环境中编译,根据错误提示查找分析并修改原程序
四、程序编写:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.List;
/**
* @Title 服务器
* @author Allen
* @version 2010-5-3 下午08:28:36
*/
public class Server {
ServerSocket server = null;
List
SimpleDateFormat sdf = new SimpleDateFormat("MM-dd HH:mm:ss");
public void begin(){
//读取客户端的userName
BufferedReader bufUserName = null;
boolean started = false;
String userName = null;
try {
server = new ServerSocket(8888);
System.out.println("服务器启动成功! 端口" + server.getLocalPort() + "监听中...");
started = true;
while(started){
Socket socket = server.accept();
bufUserName = new BufferedReader(new InputStreamReader(socket.getInputStream()));
userName = bufUserName.readLine();
System.out.println("用户:" + userName + " IP: " + socket.getLocalSocketAddress() + " client connect...");
//bufUserName.close();
SC sc = new SC(socket);
new Thread(sc).start();
clients.add(sc);
}
} catch (IOException e) {
System.out.println("端口启动失败..." + e.getMessage() + "\n 程序安全退出...");
System.exit(0);
}
}
public static void main(String[] args) {
new Server().begin();
}
private class SC implements Runnable{
BufferedReader br = null;
BufferedWriter bw = null;
Socket socket = null;
boolean isConnect = false;
public SC(Socket socket){
this.socket = socket;
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
isConnect = true;
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendMessage(String str){
try {
//bw.write(str + sdf.format(new Date()) + "\n");
bw.write(str);
bw.newLine();
bw.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
try{
String strRead = null;
while(isConnect){
while((strRead = br.readLine()) != null){
System.out.println("Server readLine..." + strRead);
for(int i = 0; i < clients.size(); i++){
clients.get(i).sendMessage(strRead);
}
}
}
}catch(Exception e){
try {
br.close();
socket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
e.getStackTrace();
}finally{
try {
if(br != null) br.close();
if(bw != null) bw.close();
if(socket != null) {
socket.close();
//s = null;
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.*;
/**
* @Title 客户端
* @author Allen
* @version 2010-5-3 下午08:28:47
*/
public class Client extends JFrame {
Socket socket = null;
JTextField jname = null;
JTextField text = new JTextField();
JTextArea area = new JTextArea(10, 40);
BufferedReader br = null;
BufferedWriter bw = null;
BufferedWriter name_buf = null;
boolean connected = false;
SimpleDateFormat sdf = new SimpleDateFormat("MM-dd HH:mm:ss");
static String userName = null;
public Client(){
initFrame();
}
public static void main(String[] args) {
new Client();
}
public String getUserName(){
return userName;
}
public void initFrame(){
//setTitle(userName);
setSize(400, 300);
setLocation(500, 200);
this.setResizable(false);
JPanel panel = new JPanel();
GridBagConstraints gbc = new GridBagConstraints();
//GridBagLayout layout = new GridBagLayout();
FlowLayout layout = (FlowLayout)panel.getLayout();
layout.setAlignment(FlowLayout.RIGHT);
gbc.anchor = GridBagConstraints.LINE_END;
JButton btn_send = new JButton("send");
JButton btn_clear = new JButton("clear");
panel.setLayout(layout);
panel.add(btn_clear);
panel.add(btn_send, gbc);
area.setLineWrap(true);
area.setEditable(false);
JScrollPane jsp = new JScrollPane(area);
this.add(jsp, BorderLayout.NORTH);
this.add(panel, BorderLayout.CENTER);
this.add(text, BorderLayout.SOUTH);
pack();
SendListener sendListener = new SendListener();
btn_send.addActionListener(sendListener);
text.addActionListener(sendListener);
btn_clear.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
text.setText("");
area.setText("");
text.requestFocus();
}
});
//窗体监听
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
disConnect();
System.exit(0);
System.out.println("窗体关闭了");
}
}
setVisible(true);
connect();
ClientThread client = new ClientThread();
new Thread(client).start();
setTitle(userName);
}
//监听发送信息方法
private class SendListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
String str = text.getText();
//area.setText(area.getText() + str + " " + sdf.format(new Date()) + "\n");
text.setText("");
text.requestFocus();
try {
bw.write( userName + " 说: " + str);
bw.newLine();
bw.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
//连接服务器方法
public void connect(){
try {
socket = new Socket("127.0.0.1", 8888);
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
connected = true;
new SetNameJTextField(this);
} catch (UnknownHostException e) {
System.out.println("端口错误!" + e.getMessage());
} catch (IOException e) {
e.printStackTrace();
}
}
//关闭方法
public void disConnect(){
if(bw != null){
try {
bw.close();
bw = null;
} catch (IOException e1) {
e1.printStackTrace();
}finally{
if(br != null){
try {
br.close();
br = null;
} catch (IOException e1) {
e1.printStackTrace();
}finally{
if(socket != null){
try {
socket.close();
socket = null;
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}
}
}
//client 读取操作 线程
private class ClientThread implements Runnable {
String str = null;
public void run() {
try {
while(connected){
while((str = br.readLine()) != null){
String s = str +" "+ sdf.format(new Date()) + "\n";
area.setText( area.getText() + s);
//设置JTextArea内容过多是聚焦
area.setCaretPosition(area.getText().length());
System.out.println("Server to Client..." + str);
}
}
} catch (IOException e) {
System.out.println("Client 退出了!");
System.exit(0);
}
}
}
//设置名字窗体
private class SetNameJTextField extends JFrame{
JButton btn_setName = null;
Client c =null;
public SetNameJTextField(final Client c){
JFrame frame = new JFrame();
this.c = c;
frame.setTitle("Scanner UserName...");
frame.setSize(300, 130);
frame.setLocation(550, 250);
JPanel panel = new JPanel();
jname = new JTextField(16);
btn_setName = new JButton("OK");
panel.add(new JLabel("UserName:"));
panel.add(jname);
panel.add(btn_setName);
frame.add(panel);
frame.setVisible(true);
SetUserNameListener nameListener = new SetUserNameListener(c, frame);
btn_setName.addActionListener(nameListener);
jname.addActionListener(nameListener);
}
}
private class SetUserNameListener implements ActionListener{
JFrame f = null;
Client client = null;
public SetUserNameListener(Client c, JFrame f){
this.client = c;
this.f = f;
}
public void actionPerformed(ActionEvent e) {
try {
name_buf = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
userName = jname.getText();
client.setTitle(userName);
name_buf.write(userName);
name_buf.newLine();
name_buf.flush();
//buf.close();
f.dispose();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
五、运行结果
六、实习心得和体会
这次的课程设计是简单聊天程序,在平日的生活学习中我们也经常用,比如QQ、MSN等即时通讯软件,所以这个课程设计很有现实意义,做起来也比较感兴趣。此次编程的一对多聊天工具利用了java socket套接字编程,由于对于才刚开始学习java语言,由于对java语言的不熟悉,花费了很多时间在对用到的java语言的学习,另外也搜索了一些关于JAVA socket编程的知识,关于服务器与客户端之间的通信主要借用socket编程,由serversocket soc=new serversocket(10000)构造对象监视服务器的10000端口,用socket=soc.accept();产生阻塞等待客户端连接,客户端由Socket soc=new Socket(“172.0.0.1”10000)与服务器产生连接。由Socket对象得到输入流,并构造相应的BufferedReader对象,由socketd对象得到输出流,服务器从客户端发出的输入流读取信息,编程完时程序不能运行成功,服务器与客户端并不能一对多的聊天,且不能循环,后来询问了学习java的同学,还是没有能找到原因,有在网上搜索一下,也没能有结果,后来我将System.out.println("server:"+is.readLine());从输入流读取服务器信息改为从标准输入读取信息,才运行出正确结果。通过这次实验,我全面的认识到,计算机网络方面的知识学得不够扎实,不能将知识运用到实践中去。以后要注意加强。
本文来源:https://www.2haoxitong.net/k/doc/5c13e7353968011ca300912f.html
文档为doc格式