`
ximenblog
  • 浏览: 4147 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

基于Socket通信的简单网络聊天室(1)

 
阅读更多

     通过这个简单的网络聊天室,来展示和说明Socket通信基本原理和执行方式。有什么不正不足之处,或者更好的见解,请各位牛人明示。文章的思路并非本人原创,仅仅为了自身对Socket通信编程的巩固,也借此分享给需要的人。

     TCP/IP协议是一种可靠的网络协议,是在议通信的两端各建立一个Socket,在其之间形成一个网路虚拟链路,建立好之后

两端的程序就可以通过虚拟链路进行通信。

    Java中使用Socket对象来代码两端的通信端口,且通过Socket产生的IO流进行网络通信。

    TCP通信是没有服务端、客户端区分的。在没有正式建立起虚拟链路前,必须有一方主动接收其他通信实体的链接请求。在Java中,ServerSocket负责承担此类任务。它负责监听并接受来自客户端Socket的通信请求,如果没有通信请求,则一直处于等待状态。ServerSocket包含一个方法 accept() ,当接收到一个通信请求之后,此方法则会返回一个与客户端对应Socket对象,如果没有,则处于等待状态,线程也会处于阻塞状态直到有来自客户端的通信请求

   

public class Server 
{
	private static final int SERVER_PORT = 3003;
	//使用MyMap对象来保存每个客户名字和对应输出流之间的对应关系。
	public static YeekuMap<String , PrintStream> clients =
		new YeekuMap<String , PrintStream>();
	public void init()
	{
		ServerSocket ss = null;
		try
		{
			//建立监听的ServerSocket
			ss = new ServerSocket(SERVER_PORT);
			//采用死循环来不断接受来自客户端的请求
			int i = 0;
			while(true)
			{
				Socket socket = ss.accept();
				new ServerThread_1(socket).start();
				System.out.println("---》接受一个客户端请求,创建一个线程:\t" + i);
				i++;
			}
		}
		//如果抛出异常
		catch (IOException ex)
		{
			System.out.println("服务器启动失败,是否端口" 
				+ SERVER_PORT + "已被占用?");
		}
		//使用finally块来关闭资源
		finally
		{
			try
			{
				if (ss != null)
				{
					ss.close();
				}
			}
			catch (IOException ex)
			{
				ex.printStackTrace();
			}
			System.exit(1);
		}
	}
    public static void main(String[] args)
    {
		Server server = new Server();
		server.init();
    }
}

     用一个指定端口号来创建一个ServerSocket,端口号的有效数值应该是在0~65535

ServerSocket ss = new ServerSocket(3000);

   建立一个类似与服务端的Sever类,在Server类的初始化模块中创建通信监听器,并在循环体中不断调用accept()方法接收来自其他客户端的通信请求,当接收到来自客户端的通信请求时accept()方法会返回一个与客户端对应的Socket通信实体,将其传入到一个通信线程中处理来自客户端的通信信息。如果没有接受到来自客户端的通信请求,其所在的线程将一直处于阻塞状态。

   下面是服务器通信线程的管理类,主要负责处理来自客户端通信信息的处理

 

 

package com.base.Net.Senior;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;


/**
 * 服务器线程管理类
 * @author Petter
 *
 */
public class ServerThread_1 extends Thread{
	private Socket socket;
	BufferedReader buffReader;
	PrintStream printStream;
	/**
	 * 定义构造函数,用于接受一个Socket来创建ServerThread线程
	 * @param socket
	 */
	public ServerThread_1(Socket socket){
		this.socket = socket;
	}
	@Override
	public void run() {
		try{
			//获取该Socket对应的输入流
			buffReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			//获取该Socket对应的输出流
			printStream = new PrintStream(socket.getOutputStream());
			String line = null;
			while( (line = buffReader.readLine()) != null ){
				//如果读到的行以MyProtocol.USER_ROUND开始,并以其结束
				//可以确定读到的是用户登录的用户名
				if(line.startsWith(YeekuProtocol.USER_ROUND) && line.endsWith(YeekuProtocol.USER_ROUND)){
					//获取真实的数据
					String userName = getRealMsg(line);
					System.out.println("---》用户: " + userName);
					//如果用户名重复
					if(Server.clients.containsKey(userName)){
						System.out.println("登录的用户名重复!");
						printStream.println(YeekuProtocol.NAME_REP);
					}else{
						System.out.println("登录到服务器成功!");
						printStream.println(YeekuProtocol.LOGIN_SUCCESS);
						Server.clients.put(userName, printStream);
					}
				}
				//如果得到的行以YeeKuProtocol.PRIVATE_ROUND开始,并以起结束
				//可以确定是私聊信息,私聊信息只向特定的输出流发送
				else if(line.startsWith(YeekuProtocol.PRIVATE_ROUND) && line.endsWith(YeekuProtocol.PRIVATE_ROUND)){
					//得到真实消息
					String userAndMsg = getRealMsg(line);
					//以SPLIT_SIGN来分割字符串,前面部分是私聊用户,后面部分是聊天信息
					String user = userAndMsg.split(YeekuProtocol.SPLIT_SIGN)[0];
					String msg =  userAndMsg.split(YeekuProtocol.SPLIT_SIGN)[1];
					//获取私聊用户对于的输出流
					Server.clients.get(user).println(
							Server.clients.getKeyByValue(printStream) + "悄悄的对你说:" + msg);
				}
				//公聊信息,向每个Socket发送
				else{
					//得到真实消息
					String msg = getRealMsg(line);
					//遍历Clients中的每个输出流
					for(PrintStream clientsPs : Server.clients.valueSet()){
						clientsPs.println(Server.clients.getKeyByValue(printStream) + "说:" +  msg);
					}
				}
			}
			//捕获异常后, 表明该Socket对应的客户端已经出现了问题
			//所以程序将对应的输出流从Map中删除
		}catch(IOException e){
			Server.clients.removeByValue(printStream);
			System.out.println(Server.clients.size());
		}finally{
			if(buffReader != null){
				try {
					buffReader.close();
					if(printStream != null){
						printStream.close();
					}
					if(socket != null){
						socket.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
		}
	}
	/**
	 * 将读取到的内容去掉前后协议字符串,恢复真实的数据
	 * @param line
	 * @return
	 */
	public String getRealMsg(String line){
		return line.substring(YeekuProtocol.protocol_len, line.length() - YeekuProtocol.protocol_len);
	}
}

   在通信线程管理类中,会用到 YeekuProtocol这样的通信协议类,主要是为了在接受到通信信息时区分信息种类,是公聊信息还是私聊

信息还是用户登录。

   同时,为了将某个用户的公共聊天数据或者私密聊天数据发送给其他用户,在客户端做出请求时,会再通信线程管理类中将其对应的输出流PrintStream类实体,userName保存到一个键值对的Map中,这样就可以在服务端区分是哪个用户发送的通信信息,是以公共聊天的形式发送给其他所有在线用户还是 以私密形式发送给指定的在线用户

  

package com.base.Net.Senior;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

//扩展HashMap类,MyMap类要求value也不可重复
public class YeekuMap<K,V> extends HashMap<K,V>
{
	/**
	 * 
	 */
	private static final long serialVersionUID = -1731258447378994845L;
	//根据value来删除指定项
	public void removeByValue(Object value) 
	{
		for (Object key : keySet())
		{
			if (get(key) == value)
			{
				remove(key);
				break;
			}
		}
	}

	//获取所有value组成的Set集合
	public Set<V> valueSet() 
	{
		Set<V> result = new HashSet<V>();
		//遍历所有key组成的集合
		for (K key : keySet())
		{
			//将每个key对应的value添加到result集合中
			result.add(get(key));
		}
		return result;
	}

	//根据value查找key。
	public K getKeyByValue(V val) 
	{
		//遍历所有key组成的集合
		for (K key : keySet())
		{
			//如果指定key对应的value与被搜索的value相同
			//则返回对应的key
			if (get(key).equals(val) 
				&& get(key) == val)
			{
				return key;
			}
		}
		return null;
	}
	//重写HashMap的put方法,该方法不允许value重复
	public V put(K key,V value)
	{
		//遍历所有value组成的集合
		for (V val : valueSet() )
		{
			//如果指定value与试图放入集合的value相同
			//则抛出一个RuntimeException异常
			if (val.equals(value) 
				&& val.hashCode() == value.hashCode())
			{
				throw new RuntimeException
					("MyMap实例中不允许有重复value!"); 
			}
		}
		return super.put(key , value);
	}
}

 

 

 

 

  • 大小: 90.6 KB
  • 大小: 122.3 KB
  • 大小: 125.4 KB
  • Net.zip (15.5 KB)
  • 下载次数: 2
分享到:
评论

相关推荐

    C# WinForm使用Socket通信搭建简易聊天室

    在本文中,我们将深入探讨如何使用C# WinForm和Socket通信技术来搭建一个简单的聊天室。Socket编程是网络通信的基础,而C# WinForm则提供了一个用户友好的图形界面,两者结合可以创建出功能丰富的交互式应用。 首先...

    VC++基于SOCKET的简易网络聊天室

    本项目“VC++基于SOCKET的简易网络聊天室”利用Microsoft Visual C++(简称VC++)作为开发环境,结合Socket接口实现了一个简单的多人聊天平台。下面将详细介绍这个项目涉及的关键知识点。 1. **Socket基础**:...

    Android基于Socket的简单的聊天室,代码有注释,易学,易懂

    在Android平台上构建一个基于Socket的简单聊天室是一个学习网络编程和多用户交互的好项目。这个项目的核心在于使用Socket通信协议,让多个设备之间能够通过网络交换消息。下面将详细讲解这个项目的实现步骤、关键...

    基于socket通信--聊天室VC

    【基于Socket通信--聊天室VC】是一个使用C++编程语言构建的简单聊天室应用程序,它利用了套接字(Socket)技术进行网络通信。Socket是网络编程中的基本接口,允许两个或更多的进程通过网络进行通信。在这个项目中,...

    c++基于socket的网络聊天室

    ### c++基于socket的网络聊天室 #### 一、引言 在当今互联网技术高度发达的时代,基于网络的即时通信应用已经成为人们日常生活中不可或缺的一部分。其中,基于C++语言开发的网络聊天室作为一种典型的应用场景,不仅...

    基于socket.io的聊天室

    总结来说,这个基于socket.io的聊天室项目是学习实时通信和Node.js开发的一个理想实践。它涵盖了Web应用开发的关键组件,包括Express后端、实时通信的Socket.IO以及简单的HTML前端。通过深入理解并实践这个项目,...

    基于C#socket通信的tcp多人聊天室.zip

    本项目"基于C# Socket通信的TCP多人聊天室"就是利用C#的Socket类实现了一个简单的多人聊天室,它通过TCP协议建立客户端和服务端之间的连接,允许多个客户端同时连接并进行实时通信。 【描述】中的关键知识点: 1. ...

    基于多线程和SOCKET聊天室

    综上所述,"基于多线程和SOCKET聊天室"项目展示了如何在C#环境下利用多线程和Socket技术实现一个简单的聊天室。它不仅涵盖了网络编程的核心概念,还涉及到UI设计和并发处理,对于学习和理解这些技术具有很高的实践...

    基于socket.io聊天室功能

    在这个“基于socket.io聊天室功能”的项目中,我们将探讨如何使用 Socket.IO 构建一个简单的聊天室应用。 1. **Socket.IO 的基本概念** - **事件驱动**:Socket.IO 的通信基于事件模型,客户端和服务器通过发送和...

    unix c++ 基于socket的简单的聊天室代码

    本示例将深入讲解如何使用Unix环境下的C++实现一个基于TCP Socket的简单多人聊天室。这个项目涉及了多个关键知识点,包括Socket接口、TCP协议、多线程以及并发处理。 首先,Socket是操作系统提供的一个接口,允许...

    基于socket通讯的聊天室

    本项目"基于Socket通讯的聊天室"采用C#编程语言,利用客户端-服务器模式来构建一个简单的实时聊天系统。这里我们将深入探讨相关知识点。 首先,**C#**是一种面向对象的编程语言,由微软公司开发,广泛应用于Windows...

    基于socket和tkinter的python网络聊天室程序

    在这个项目中,我们将深入探讨如何使用Python的socket模块创建一个网络聊天室,并结合tkinter库构建一个友好的图形用户界面。 首先,socket模块是Python提供的网络通信基础库,它允许程序作为服务器或客户端在...

    C语言基于socket多人聊天(包含注册登录)

    在本项目中,"C语言基于socket多人聊天(包含注册登录)"是一个使用C语言开发的网络应用程序,它利用了socket编程来实现一个简单的聊天室功能。这个程序具有用户注册和登录的功能,只有验证通过的用户才能发送信息。...

    基于Socket的简单聊天室

    总的来说,通过这个基于Socket的简单聊天室项目,我们可以学习到网络编程的基础知识,理解Socket通信的原理,以及如何利用这些知识创建一个基本的多人聊天应用。这个过程不仅加深了对TCP/IP协议的理解,也锻炼了实际...

    j2se基于socket通信的聊天室

    "j2se基于socket通信的聊天室"是一个很好的学习实践项目,它能够帮助初学者理解如何使用Java标准版(J2SE)的Socket API进行基本的网络通信。在这个项目中,我们将探讨以下关键知识点: 1. **Socket概念**:Socket...

    基于Socket的as3的小型聊天室

    【标题】"基于Socket的as3的小型聊天室"是一个使用ActionScript 3(AS3)编程语言开发的网络通信应用实例,它构建了一个简单的聊天室客户端。在互联网编程中,Socket是实现客户端与服务器之间实时通信的基础技术,它...

    基于Socket聊天室

    总的来说,"基于Socket聊天室"项目涵盖了网络编程中的核心概念,如TCP连接、Socket通信、文件传输,以及GUI编程的基本原理。这个项目对于理解和实践网络编程有着重要的实践价值,同时也有助于提升开发者在多线程和...

    python下基于socket通信聊天室.zip

    本项目“python下基于socket通信聊天室”提供了一个实际应用示例,旨在教授如何构建一个简单的聊天室系统。这里我们将深入探讨相关知识点。 首先,让我们了解什么是Socket。Socket是操作系统提供的一种接口,它允许...

    c++聊天室 MFC工程 , socket通信

    __介绍__:利用socket通信机制实现简单的聊天室功能 __开发工具__:visual studio 2012 __开发平台__:windows8 , MFC工程 , socket通信 实现的__功能__有: * 账号登录和注册 * 用户之间互相发送在线消息 * ...

    模仿QQ通信的socket聊天室

    通过分析和理解代码,我们可以掌握如何构建一个简单的网络聊天应用,这对于深入理解网络编程和并发处理至关重要。同时,这也是模拟大型即时通讯软件如QQ工作原理的一个基础模型,有助于我们更好地理解其背后的复杂...

Global site tag (gtag.js) - Google Analytics