通过这个简单的网络聊天室,来展示和说明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);
}
}
相关推荐
__介绍__:利用socket通信机制实现简单的聊天室功能 __开发工具__:visual studio 2012 __开发平台__:windows8 , MFC工程 , socket通信 实现的__功能__有: * 账号登录和注册 * 用户之间互相发送在线消息 * ...
C#实现的简单多人界面聊天室,原理是服务端通过TCP连接转发该客户端的信息给其他客户端
java实现socket编程网络通信多人聊天室,可以实现简单的多人聊天功能。适合初学的大二,大三学生,学习。
本项目实现了在Linux下简单的socket网络聊天室。在linux下编写并调试服务器端程序和客户端程序,实现了服务器、客户端之间的连接和通信。可以在单机上开辟两个终端窗口分别运行客户、服务器端的程序,或者将两台主机...
c#基于TCP协议的Socket通信完整实例(实现多人聊天室),通过C#winform实现多人聊天,同时服务器可以向指定客户端发送消息
本课程设计实现了在linux下简单的网络聊天室。在Linux下编写并调试服务器端程序和客户端程序,实现了客户、服务器之间的连接和通信。可以在单机上开辟两个窗口分别运行客户、服务器端的程序,或者将两台主机连接分别...
基于C++和win32的简单多人聊天室,通信采用socket.zip
简单的聊天室程序 本题是一个简单的聊天室程序,采用客户/服务器模式,分为客户端程序和服务器端程序。由于服务器只能支持一个客户,实际上是一个点对点通信的程序。客户端程序和服务器程序通过网络交换聊天字符串...
简单的聊天室程序 本题是一个简单的聊天室程序,采用客户/服务器模式,分为客户端程序和服务器端程序。由于服务器只能支持一个客户,实际上是一个点对点通信的程序。客户端程序和服务器程序通过网络交换聊天字符串...
使用套接字(Socket、ServerSocket)创建一个应用程序,实现网络数据的传输。 实现客户端和服务器端的通信。 含客户端服务器图形用户界面
网络编程课程设计-简单的聊天室程序设计 当今世界正处于信息时代,计算机和通信网络是这一时代所谓“信息基础设施”。在互联网相当普及的今天,在互联网上聊天对很多“网虫”来说已经是家常便饭了。聊天室程序可以...
主要为大家详细介绍了Android网络编程之Socket通信实现简单聊天室,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
本文出自:53078485群大咖Aran StreamSocket属于UWP中的网络通信开发技术,UWP中的StreamSocket...为了更深入的了解StreamSocket的使用,接下来几篇博客中我会结合一个聊天室的实例来从头到尾做一个简单的UWP版聊天室。
用Java写的基于UDP无连接的简单图形界面聊天程序,可实现内网或外网运行本程序计算机的文本通信聊天,可群聊
如何使用socket利用udp创建简单的聊天室呢? socket编程中,利用网络协议之UDP,实现客户端和服务器端的双端通信 对于学习中的三次握手连接,四次握手释放,已经listen()读写操作,等等希望对每一个学生和相关专业...
主要为大家详细介绍了Python socket实现简单聊天室,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
《Linux + socket多线程并发服务端+ 聊天室》 介绍是服务端和多个客户端之间可以交换信息的简单的聊天程序。 使用多线程并发技术,Socket网络通信
用socket套接字实现了文件传输,尤其适用于初学者学习socket进行创建,绑定,监听,接收等过程,服务器端和客户端进行通信的整个流程,MFC界面简单。发送端有,create ,listen,accept,send等函数;接收端有create...
基于TCP/IP的通信基本上都是利用SOCKET套接字进行数据通讯,程序分为服务器端和用户端两部分 本实验是本人做的计算机网络课程设计,有mfc的CSocket编的..给大家分享下 支持多人聊天,可以用,先运行服务器端,点击监听,...
广工 java与计算机网络的作业大作业,java聊天室,需要的自取