1 引言
Java 是一种可以编写跨平台应用软件的面向对象的程序设计语言,网络应用是
Java 语言取得成功的领域之一,它已经成为现在 Internet 上最流行的一种编程语言。
网络编程的目的就是直接或间接地通过网络协议与其它计算机进行通讯。两台计算
机通讯需解决两个主要问题:一是如何准确定位网络上的主机;二是找到主机后如
何可靠有效地进行数据传输。
Java 语言作为网络编程语言,提供了强大的网络编程接口。针对网络通信的不
同层次,Java 提供的网络功能有四大类:InetAddress、URL、Socket、Datagram。Socket
是 Internet 使用的协议组 TCP/IP 的组合,实现了两台主机之间通过端口进行网络通
信。Java.net 包中提供 Socket 类,隐藏了 Socket 的实现细节,不需要开发者编写接
口程序,而可以快速的实现网络的通信。[1]
2 Socket 的通信
2.1 Socket 通信机制
在 Java 中,可以使用两种 Socket 方式,即流式 Socket 和数据报式 Socket。流
式 Socket 提供了双向的、有序的、无重复、可靠的的数据流服务,采用的是一种 TCP
协议。数据报式 Socket 支持双向的数据流,但不保证是可靠的、有序的、无重复的
传输,采用的是 UDP 协议。[1]两种 Socket 相比较而言,流式 Socket 具有较高的安
全性,但有一定的额外开销。而数据报式 Socket 与之相反。笔者根据实际情况采用
的是流式 Socket 方式。
基于 TCP 协议的流式 Socket 实现网络通信的类有两个:在客户端的 Socket 类
和在服务器端的 ServerSocket 类。无论一个 Socket 通信程序的功能多么齐全,程序
多么复杂,Socket 基本
结构都是一样的,都包括以下四个基本步骤:
(1)在客户端和服务器端创建 Socket 和 ServerSocket 实例;
(2)打开连接到 Socket 的输入/输出流;
(3)利用输入/输出流,按照一定的协议对 Socket 进行读/写操作;
(4)关闭输入/输出流和 Socket。
Socket 通信机制框图见图 1。
2.2 Socket 的多客户端并发通信
支持多个客户端的 Socket 通信实现方法有多种:方法一,在一台计算机上一次
启动多个服务器程序(端口号必须不同);方法二,将服务器程序写成多线程的,不
同处理线程为不同的客户服务,主线程只负责循环等待,处理线程负责网络连接,
接收客户输入的信息。
实现多个客户与服务器并发通信,就像服务器与自己连接一样,笔者认为最好
引入多线程机制。多线程正好是 Java 提供的一个重要机制,支持多个程序并发执行。
服务器端每当建立一个新的 Socket 连接,主线程就启动一个新的线程,负责服务器
与客户端的通信;而主线程继续等待下一个客户端的连接。当客户端断开连接后,
子线程释放其占用的所有 Socket 资源[3]。多线程支持多客户端的具体框图见图 2。
3 多客户端聊天程序的设计
系统主要分为两大部分:TCP 服务器 Server 和客户端 Client。
3.1 服务器端程序编写
服务器端等待用户连接,如有用户发送连接请求后,创建一个用户实例,记录
客户端的相关信息,维护与该用户的连接。根据聊天的接收人信息,再将接收的数
据传输给客户端。当用户断开连接时,关闭用户实例,断开此用户连接。[2]主要步
骤如下:
(1) 启动服务器
try {
server=new ServerSocket(port);//初始化服务器套接字
while(true){socket=server.accept(); //等待客户连接
System.err.println(socket.getInetAddress()+"连接\n"); //得到客户机地址
Client client=new Client(socket);//实例化一个客户线程
clients.addElement(client);//增加客户线程到向量中
client.start(); //启动线程
notifyChatRoom(); //监视聊天室连接变化
} }catch(Exception ex) {
ex.printStackTrace(); //输出出错信息}
(2) 更新在线用户
for(int i=0;i
{//elementAt 方法返回在特定位置的元素,返回的元素为 Object
对象
Client c=(Client)clients.elementAt(i);
newUser.append(":"+c.name);//客户端姓名字符串,取得客户端的名字
}sendClients(newUser); //把取得的客户端名字发送给每个客户端
(3) 多线程的实现
聊天室的服务器采用多线程实现,每当一个新的用户连接到服务器时,就实例
化一个新的线程来与该客户端通信。Client 类负责维护客户端的相关信息,比如 IP
地址、聊天室中的用户名、连接端口等,并实现了信息发送的 send 方法。主要代码
如下。
//得到输入流
BufferedReader
reader
=
new
BufferedReader(new
InputStreamReader(s.getInputStream()));
PrintStream ps=new PrintStream(s.getOutputStream()); //得到输出流
String info=reader.readLine(); //读取接受到的信息
ps.println(msg); //输出信息
ps.flush();
public void run(){while(true){
String line=null;
try{line=reader.readLine();//读取数据流
}catch(IOException ex){
ex.printStackTrace(); //输出错误信息
MyChatServer.disconnect(this); //断开连接
MyChatServer.notifyChatRoom(); //更新信息
return;}
……
3.2 客户端程序编写
提供良好的用户界面,便于用户连接、查看在线用户、发送信息。当与服务器
建立连接后,发送聊天信息。同时,检测服务器端有无数据发送,接收数据,更新
显示。
(1)界面设计(代码略)
(2)事件处理
建立连接的事件处理代码:
try{if (socket==null){
socket= new Socket(InetAddress.getLocalHost(),5656); //实例化一个套接字
ps=new PrintStream(socket.getOutputStream());//获取输出流
StringBuffer info=new StringBuffer("INFO: ");
String userinfo=jTextField1.getText()+":"+InetAddress.getLocalHost().toString();
ps.println(info.append(userinfo)); //输出信息
ps.flush();
listen=new Listen(this,jTextField1.getText(),socket); //实例化监听线程
listen.start(); /启动线程
}}catch (Exception ex){}
发送信息的代码:
if(socket!=null){StringBuffer msg=new StringBuffer("MSG: ");
String msgtxt=new String(jTextField2.getText());
ps.println(msg.append(jTextField2.getText())); //发送信息
ps.flush();
(3)监听线程的实现
Listen 类用于与服务器进行通信,并维护一些连接信息。部分代码如下。
public Listen(MyChatClient p,String n,Socket s) {
……
public void run(){
String msg=null;
while(socket!=null){
try{msg=reader.readLine();//读取服务器端传来信息
}catch(IOException ex){
client.disconnect(); //出错则断开连接
}if (msg==null) { /从服务器传来的信息为空则断开此次连接
client.listen=null;
client.socket=null;
client.list1.removeAll();
return;}……}}
3.3 运行结果
本程序的运行界面如图 3 所示。
4 结束语
Java 语言具有平台独立、面向对象、多线程、简单性、解释性等许多优点,是
目前广泛流行的编程语言。笔者使用 Socket 与多线程机制相结合的方法,编写了简
便的客户端与服务器的并发通信聊天程序。此程序具有成本低、节省带宽和跨平台
可移植性的优点。随着宽带网络的进一步发展,我们还可以开发基于 Socket 的多人
视频聊天软件。