网络上机--聊天程序(java)

内容

   基于TCP-面向连接的聊天程序

实现功能:

   一:是监听某端口, 建立与客户的Socket连接,处理一个客户的连接后,能很快再进入监听状态;
   二:是处理与客户的通信,由于聊天是在客户之间进行的,所以服务器的职责是将客户发送的消息转发给其他客户。
   三:判断用户时是否在线,如果用户未登录,这他将不能收到消息。
   四:处理用户下线,当用户下线后,他将不能再接受消息,也不能发送消息,但是可以看到自己的聊天天记录,除非再次登录才可以收发消息。
   五:细节部分,当聊天区域过长,文本框可以上下或者左右滚动。因为是多人聊天,所以发出的每条消息自带用户名。服务器上可以显示有多少个用户连接已成功建立。用户离线,会向其他用户发出提示。

代码关键

  1. 首先,解决通信问题。在服务器端创建一个 ServerSocker对象,通过执行acceptO方法监听客户连接,这将使线程处于等待状态,然后在客户端建立Socket类,与某服务器的指定端口进行连接。服务器监听到连接请求后,就可在两者之间建立连接。连接建立之后,就可以取得相应的输入输出流进行通信。一方的输出流发送的数据将被另一方的输入流读取。
    Alt
  2. 此外,实现客户收发消息。借助多线程技术,我们在服务器为每个成功连接的客户连接建立一个通信线程,通信线程负责接受客户的消息并将消息转发给其他客户。服务器循环监听客户连接,每个客户连接成功后,创建一个通信线程,并将与Socket 对应的输入输出流传给该线程。

运行截图

界面展示

Alt

先登录才能收发消息:

图1
图2

离线给其他用户提示

Alt

需要重新登录才能重新收发消息:

Alt

服务器提示连接数:

Alt在这里插入图片描述

源程序:

服务器端:

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) {}
			
		}
	}
}

备注

  先运行服务器端,再运行客户端

猜你喜欢

转载自blog.csdn.net/qq_41571459/article/details/84885008
今日推荐