网络上机--聊天程序

内容:使用java语言编写基于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);//之前参数打成display了
		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) {}
			
		}
	}
}


备注:
	先运行服务器端,再运行客户端