内容:
基于TCP-面向连接的聊天程序
实现功能:
一:是监听某端口, 建立与客户的Socket连接,处理一个客户的连接后,能很快再进入监听状态;
二:是处理与客户的通信,由于聊天是在客户之间进行的,所以服务器的职责是将客户发送的消息转发给其他客户。
三:判断用户时是否在线,如果用户未登录,这他将不能收到消息。
四:处理用户下线,当用户下线后,他将不能再接受消息,也不能发送消息,但是可以看到自己的聊天天记录,除非再次登录才可以收发消息。
五:细节部分,当聊天区域过长,文本框可以上下或者左右滚动。因为是多人聊天,所以发出的每条消息自带用户名。服务器上可以显示有多少个用户连接已成功建立。用户离线,会向其他用户发出提示。
代码关键
- 首先,解决通信问题。在服务器端创建一个 ServerSocker对象,通过执行acceptO方法监听客户连接,这将使线程处于等待状态,然后在客户端建立Socket类,与某服务器的指定端口进行连接。服务器监听到连接请求后,就可在两者之间建立连接。连接建立之后,就可以取得相应的输入输出流进行通信。一方的输出流发送的数据将被另一方的输入流读取。
- 此外,实现客户收发消息。借助多线程技术,我们在服务器为每个成功连接的客户连接建立一个通信线程,通信线程负责接受客户的消息并将消息转发给其他客户。服务器循环监听客户连接,每个客户连接成功后,创建一个通信线程,并将与Socket 对应的输入输出流传给该线程。
运行截图:
界面展示
先登录才能收发消息:
|
|
离线给其他用户提示
需要重新登录才能重新收发消息:
服务器提示连接数:
源程序:
服务器端:
package unit16;
import java.net.*;
import java.io.*;
import java.util.*;
public class TalkServer
{
public static ArrayList<Client> allclient=new ArrayList<Client>();//存放所有客户的通信线程
public static int clientnum=0;
public static ArrayList<Integer> flag=new ArrayList<Integer>();
public static void main(String[] args) throws Exception
{
// TODO 自动生成的方法存根
try
{
ServerSocket s=new ServerSocket(5432);
while(true)
{
Socket s1=s.accept();
DataOutputStream dos=new DataOutputStream(s1.getOutputStream());
DataInputStream din=new DataInputStream(s1.getInputStream());
Client x=new Client(clientnum,dos,din);//创建线程
allclient.add(x);
x.start();
clientnum++;
System.out.println(clientnum +" connections have been established");
}
}catch(Exception e) {}
}
}
class Client extends Thread
{
int id;
DataOutputStream dos;//去往客户的输出流
DataInputStream din;//来自客户的输入流
public Client(int id,DataOutputStream dos,DataInputStream din)
{
this.id=id;
this.dos=dos;
this.din=din;
}
public void run()//启动线程,自动执行run
{
while (true)//循环读取客户数据,转发给其他用户
{
try
{
String message=din.readUTF();//读客户数据 ***:***
if(message.contains("离线"))
TalkServer.flag.add(id);
for(int i=0;i<TalkServer.clientnum;i++)
{
int f=0;
for(int k=0;k<TalkServer.flag.size();k++)
{
if(TalkServer.flag.get(k)==i)
{
f=1;//表明在下线名单里
break;
}
}
if(f!=1 || TalkServer.flag.size()==0 ) //没在下线名单 或者 下线名单为空时
TalkServer.allclient.get(i).dos.writeUTF(message);//将消息转发给所有用户
}
}catch(Exception e) {}
}
}
}
客户端:
package unit16;
import java.net.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
public class TalkClient
{
static String user=null;
static String flag="";
public static void main(String[] args) throws Exception
{
// TODO 自动生成的方法存根
Socket s1=new Socket("127.0.0.1",5432);
DataInputStream dis=new DataInputStream(s1.getInputStream());
final DataOutputStream dos=new DataOutputStream(s1.getOutputStream());
Frame myframe=new Frame("简易聊天室");
Panel panelx=new Panel();
Panel panelx2=new Panel();
TextArea display=new TextArea(5,20);
final TextField input=new TextField(40);
final TextField u = new TextField(20);
final Button login = new Button("登录");
final Button out = new Button("离线");
final Label name = new Label("姓名:");
final Button send = new Button("发送");
//panelx.add(display);
panelx.add(name);
panelx.add(u);//新加
panelx.add(login);//新加
panelx.add(out);//新加
panelx2.add(input);
panelx2.add(send);
myframe.add("North",panelx);
myframe.add("South", panelx2);
myframe.add("Center", display);
ScrollPane scrollPane = new ScrollPane();
scrollPane.add(display);
myframe.add(scrollPane);
new receiveThread(dis,display);//创建线程自动启动run
input.setEnabled(false);//登录前输入框为空
login.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
user = u.getText();
login.setEnabled(false);
input.setEnabled(true);
out.setEnabled(true);
}
});
out.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
flag ="已离线";
out.setEnabled(false);
login.setEnabled(true);
input.setEnabled(false);
try
{
dos.writeUTF(user + ":"+ flag+ input.getText());
}catch(Exception z){}
}
});
send.addActionListener( new ActionListener(){//定义一个实现ActionListener接口的匿名内嵌类P129
public void actionPerformed(ActionEvent e)
{
try
{
dos.writeUTF(user + ":"+ flag+ input.getText());
}catch(Exception z){}
input.setText("");
}
});//意思是创建一个实现ActionListener接口的匿名内嵌类对象
myframe.setSize(400, 400);
myframe.setVisible(true);
}
}
class receiveThread extends Thread
{
DataInputStream dis;
TextArea displayarea;
public receiveThread(DataInputStream dis,TextArea m)
{
this.dis=dis;
displayarea=m;
this.start();
}
public void run()
{
for(;;)//即无限循环
{
try
{
String str=dis.readUTF();
if(TalkClient.user!=null)
displayarea.append(str+"\n");
}catch(Exception e) {}
}
}
}
备注
先运行服务器端,再运行客户端