Java使用多线程实现Socket多客户端的通信
要想详细了解socket,大家请自行百度,我这里只简单介绍。
在网络中,我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程。而socket编程就是为了完成两个唯一进程之间的通信(一个是客户端,一个是服务器端),其中用到的协议是TCP/UDP协议,它们都属于传输层的协议。
TCP是基于连接的协议,在收发数据前,需要建立可靠的连接,也就是所谓的三次握手。使用TCP协议时,数据会准确到达,但是效率较低。
UDP是面向非连接的协议,它不与对方建立连接,而是直接就把数据包发送过去。使用UDP协议时,传输效率高,但是不能保证数据准确到达,视频聊天,语音聊天时就用的UDP协议。
以使用TCP协议通讯的socket为例,其交互流程大概是这样子的:
服务器端 客户端
创建服务器端的socket 创建客户端的socket
绑定端口号 连接服务器端的端口
监听端口 向服务器端发送数据
接收客户端的连接请求 关闭socket
读取客户端发送数据
关闭socket
下面贴上代码:
服务器端:
package SocketStudy; import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket; public class SocketServer {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(10068);//创建绑定到特定端口的服务器Socket。
Socket socket = null;//需要接收的客户端Socket
int count = 0;//记录客户端数量
System.out.println("服务器启动");
//定义一个死循环,不停的接收客户端连接
while (true) {
socket = serverSocket.accept();//侦听并接受到此套接字的连接
InetAddress inetAddress=socket.getInetAddress();//获取客户端的连接
ServerThread thread=new ServerThread(socket,inetAddress);//自己创建的线程类
thread.start();//启动线程
count++;//如果正确建立连接
System.out.println("客户端数量:" + count);//打印客户端数量
}
} catch (IOException e) {
e.printStackTrace();
} }
}
自定义线程类:
package SocketStudy; import java.io.*;
import java.net.InetAddress;
import java.net.Socket; public class ServerThread extends Thread {
Socket socket = null;
InetAddress inetAddress=null;//接收客户端的连接 public ServerThread(Socket socket,InetAddress inetAddress) {
this.socket = socket;
this.inetAddress=inetAddress;
} @Override
public void run() {
InputStream inputStream = null;//字节输入流
InputStreamReader inputStreamReader = null;//将一个字节流中的字节解码成字符
BufferedReader bufferedReader = null;//为输入流添加缓冲
OutputStream outputStream = null;//字节输出流
OutputStreamWriter writer = null;//将写入的字符编码成字节后写入一个字节流
try {
inputStream = socket.getInputStream();
inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
bufferedReader = new BufferedReader(inputStreamReader);
String info = null;//临时 //循环读取客户端信息
while ((info = bufferedReader.readLine()) != null) {
//获取客户端的ip地址及发送数据
System.out.println("服务器端接收:"+"{'from_client':'"+socket.getInetAddress().getHostAddress()+"','data':'"+info+"'}");
} socket.shutdownInput();//关闭输入流 //响应客户端请求
outputStream = socket.getOutputStream();
writer = new OutputStreamWriter(outputStream, "UTF-8");
writer.write("{'to_client':'"+inetAddress.getHostAddress()+"','data':'我是服务器数据'}");
writer.flush();//清空缓冲区数据
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭资源
try {
if (writer != null) {
writer.close();
}
if (outputStream != null) {
outputStream.close();
}
if (bufferedReader != null) {
bufferedReader.close();
}
if (inputStreamReader != null) {
inputStreamReader.close();
}
if (inputStream != null) {
inputStream.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
} }
}
客户端:
package SocketStudy; import java.io.*;
import java.net.Socket;
import java.util.Scanner; public class SocketClient {
public static void main(String[] args) {
try {
Socket socket = new Socket("服务器的ip", 10068);
OutputStream outputStream = socket.getOutputStream();//得到一个输出流,用于向服务器发送数据
OutputStreamWriter writer=new OutputStreamWriter(outputStream,"UTF-8");//将写入的字符编码成字节后写入一个字节流
System.out.println("请输入数据:");
Scanner sc = new Scanner(System.in);
String data = sc.nextLine();
writer.write(data);
writer.flush();//刷新缓冲
socket.shutdownOutput();//只关闭输出流而不关闭连接
//获取服务器端的响应数据 InputStream inputStream = socket.getInputStream();//得到一个输入流,用于接收服务器响应的数据
InputStreamReader inputStreamReader = new InputStreamReader(inputStream,"UTF-8");//将一个字节流中的字节解码成字符
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);//为输入流添加缓冲
String info = null; System.out.println("客户端IP地址:"+socket.getInetAddress().getHostAddress());
//输出服务器端响应数据
while ((info = bufferedReader.readLine()) != null) {
System.out.println("客户端接收:" + info);
}
//关闭资源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
writer.close();
outputStream.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果(先运行服务器端,再运行客户端):
服务器:

客户端:

回车之后
客户端:

服务器端:

在cmd下运行(先编译再运行生成的.class文件,如果有中文,需要加encoding参数,当类中有导入自己创建的类时,需要切换到能包含该类的文件夹下执行命令,否则会报错)

此时的服务器端:

Java使用多线程实现Socket多客户端的通信的更多相关文章
- 《Unity 3D游戏客户端基础框架》多线程异步 Socket 框架构建
引言: 之前写过一个 demo 案例大致讲解了 Socket 通信的过程,并和自建的服务器完成连接和简单的数据通信,详细的内容可以查看 Unity3D -- Socket通信(C#).但是在实际项目应 ...
- 利用多线程使socket服务端可以与多个客户端同时通讯
利用多线程使socket服务端可以与多个客户端同时通讯 server import socket 1. 符合TCP协议的手机 server = socket.socket(socket.AF_INET ...
- 编写Java程序,使用 Socket类模拟用户加入 QQ 群时,QQ 小冰发送欢迎消息的场景(用户充当客户端,QQ 小冰充当服务端)
查看本章节 查看作业目录 需求说明: 小冰是微软公司研发的人工智能机器人,被腾讯公司加入 QQ 群后,立即受到千万网友的喜爱.现在使用 Socket类模拟用户加入 QQ 群时,QQ 小冰发送欢迎消息的 ...
- 【关于java多线程和socket通信的一些记录】---高并发/高负载/高可用/重入锁
多线程:提高cpu的使用效率,多线程是指在同一程序中有多个顺序流在执行. 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程. 线程:同一类线 ...
- Python拾忆--多线程的socket服务器
阳光明媚的午后,想想最近要开始从写Java到写Python了,就随手打开电脑来体验一下Python与Java之间的不同吧~ 记得我还在上大二的时候,那个时候才开始学Java,最感兴趣的就是Java书最 ...
- 8.多线程和Socket通信
一.多线程 1.进程的概念: 进程就是应用程序的执行实例,有独立的内存空间和系统资源.当一个应用程序没有执行的时候,它就不是一个进程. 2.进行的特征: (1)动态性:动态产生动态消亡. (2)并 ...
- 多线程服务端与客户端通信(IO是阻塞的)_02
下面是多线程的;每次服务端接受请求,会创建一个线程专门处理这个请求: 虽然是多线程的,但还是阻塞,相当于单线程处理模式 public class TimeServer { public static ...
- java基础-多线程应用案例展示
java基础-多线程应用案例展示 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.两只熊,100只蜜蜂,蜜蜂每次生产的蜂蜜量是1,罐子的容量是30,熊在罐子的蜂蜜量达到20的时候 ...
- Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制
Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制 JAVA 中原生的 socket 通信机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.co ...
随机推荐
- ZT android -- 蓝牙 bluetooth (三)搜索蓝牙
android -- 蓝牙 bluetooth (三)搜索蓝牙 分类: Android的原生应用分析 2013-05-31 22:03 2192人阅读 评论(8) 收藏 举报 bluetooth蓝牙s ...
- python基本数据类型(容器)- tuple list dict set
tuple list dict set统称为“容器” 1. 元组tuple 列表list: 1.1 同:元组( ).列表[ ] 都是有序的 1.2 异:元组不能修改,列表可以修改 1.3 注意⚠:如果 ...
- Java遇到的问题、错误——持续更新
内容:dead code.关于eclipse没有js代码提示的解决 持续更新 ######################################################## dead ...
- java String 常用方法集合
String a = "abc";String b = "abc";a==b ;//返回true,因为a,b指向的是同一个地址 String a = new S ...
- python面向对象之类成员
面向对象编程: OOP编程是利用类和对象来创建各种模型来实现对真实世界的描述,使用面向对象编程的原因一方面是因为它可以使程序的维护和扩展变得简单,并可以大大提高程序开发效率.另外,基于面向对象的程序可 ...
- 用Web技术开发客户端(一)
http://www.cnblogs.com/lefan/archive/2012/12/27/2836400.html 范怀宇(@duguguiyu)分享了<豌豆荚2.0重构时遇到的坑> ...
- 【[SDOI2013]泉】
\(hash\)+容斥 但是看到这个令人愉快的数据范围还是直接枚举子集吧 首先我们发现\(6\)这个东西简直是小的可怜,复杂度里肯定有\(2^6\)的 于是我们可以直接先枚举子集,把所有状态的对应相等 ...
- POJ3907 Build Your Home
嘟嘟嘟 题意:按逆时针或顺时针给出一个多边形,求面积. 解法:直接套用公式:\(S = \frac{1}{2}|\sum _ {i = 1} ^ {n} {v_i \times v_{i + 1}}| ...
- Kali-linux攻击路由器
前面介绍的各种工具,都是通过直接破解密码,来连接到无线网络.由于在一个无线网络环境的所有设备中,路由器是最重要的设备之一.通常用户为了保护路由器的安全,通常会设置一个比较复杂的密码.甚至一些用户可能会 ...
- mongodb3.2副本集配置
网上的资料太乱了,等弄好了再看官网才发现官网写的最清晰和简洁 推荐官网的副本集配置:https://docs.mongodb.com/manual/tutorial/deploy-replica-se ...