传输层协议TCP、UDP,但它们毕竟只是协议,看不见摸不着,那我们怎们通过TCP、和UDP进行实际传输呢?不用着急,等看完这篇文章你一定会明白的

Socket概述

Socket中文意思为插座的意思,专业术语称之为套接字,它把TCP/IP封装成了调用接口供开发者调用,也就是说开发者可以通过调用Socket相关API来实现网络通讯。在Java中也存在Socket相关API,主要分为两个,分别是基于UDP传输协议的Socket和基于TCP传输协议的Socket,本篇文章会对基于这两种传输协议的Socket进行详细描述。

UDP Socket

通过上节的内容我们知道UDP是无连接的,只要提供对方的IP地址和端口号就能进行数据的传输,其中IP负责定位主机端口负责定位应用。知道了目标IP和目标端口号通过Java中的UDP Socket就能进行IO传输,我们来看一下具体的代码体现

/**
* 发送方UDP
*/
public class UDPSocketSend {public static void main(String[] args) throws IOException {System.out.println("Sender Start...");//1.创建socket服务DatagramSocket ds = new DatagramSocket();//2.封装数据String str = "Did you recite words today";byte[] bytes = str.getBytes();//地址InetAddress address =InetAddress.getByName("192.168.31.137");//参数:数据、长度、地址、端口DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,6666);//3.发送数据包ds.send(dp);//4.关闭socket服务ds.close();}/**
* 接收方UDP
*/
public class UDPSocketReceive{public static void main(String[] args) throws IOException {System.out.println("Receiver Start...");//1.创建udp的socket服务,并声明端口号DatagramSocket ds = new DatagramSocket(6666);//2.创建接收数据的数据包byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes,bytes.length);//3.将数据接收到数据包中,为阻塞式方法ds.receive(dp);//4.解析数据InetAddress address = dp.getAddress();//发送方IPint port = dp.getPort();//发送方端口String content = new String(dp.getData(),0,dp.getLength());System.out.println("address:"+address+"---port:"+port+"---content:"+content);//关闭服务ds.close();}
}

分别启动发送方和接收方,我们来看一下打印结果

发送方:

Sender Start...

接收方:

Receiver Start...
address:/192.168.31.137---port:65037---content:Did you recite words today

成功接收到消息,并打印出发送方IP和端口,下面我来个大家撸一遍步骤

发送方:
首先创建udp的socket服务
将需要发送的数据放在数据包DatagramSocket中,DatagramSocket会根据UDP协议对数据包、IP、端口号进行封装
通过udp的socket服务将数据包发送
最后将udp服务关闭
接收方:
创建udp的socket服务,并且明确自己的端口号
创建DatagramSocket用来解析数据接收到的数据包
将数据接收到数据包DatagramSocket中
通过DatagramSocket解析数据
关闭服务

整个UDP发送数据的流程就是这样

注意点:
为UDP是无连接的不可靠传输,所以接收方需要在发送方发送数据之前就启动,否则会接收不到数据,也就是说必须先运行UDPSocketReceive再运行UDPSocketSend。

聊天实例

把上面的例子进行一些小改动就可以实现聊天功能

public class UDPSocket1 {public static void main(String[] args) {try {new Thread(new Runnable() {@Overridepublic void run() {try {receive();} catch (IOException e) {e.printStackTrace();}}}).start();send();} catch (IOException e) {e.printStackTrace();}}//接收消息方法private static void receive() throws IOException {System.out.println("UDOSocket1 Receiver Start...");//1.创建udp的socket服务,并声明端口号DatagramSocket ds = new DatagramSocket(6666);//无限循环,一直处于接收状态while (true) {//2.创建接收数据的数据包byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes, bytes.length);//3.将数据接收到数据包中ds.receive(dp);//4.解析数据String content = new String(dp.getData(), 0, dp.getLength());System.out.println("UDPSocket1 Receive:" + content);}}private static void send() throws IOException {//1.创建socket服务DatagramSocket ds = new DatagramSocket();//将键盘输入的信息转换成输入流再放入到缓冲区BufferedReader br = new BufferedReader(new InputStreamReader(System.in));String line = null;while ((line=br.readLine())!=null){//2.封装数据byte[] bytes = line.getBytes();//地址InetAddress address =InetAddress.getByName("192.168.31.137");//参数:数据、长度、地址、端口DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,7777);//3.发送数据包ds.send(dp);}//4.关闭socket服务ds.close();}
}public class UDPSocket2 {public static void main(String[] args){try {new Thread(new Runnable() {@Overridepublic void run() {try {receive();} catch (IOException e) {e.printStackTrace();}}}).start();send();} catch (IOException e) {e.printStackTrace();}}//接收消息方法private static void receive() throws IOException {System.out.println("UDOSocket2 Receiver Start...");//1.创建udp的socket服务,并声明端口号DatagramSocket ds = new DatagramSocket(7777);//无限循环,一直处于接收状态while (true) {//2.创建接收数据的数据包byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes, bytes.length);//3.将数据接收到数据包中ds.receive(dp);//4.解析数据String content = new String(dp.getData(), 0, dp.getLength());System.out.println("UDPSocket2 Receive:" + content);}//关闭服务
//        ds.close();}private static void send() throws IOException {//1.创建socket服务DatagramSocket ds = new DatagramSocket();//将键盘输入的信息转换成输入流再放入到缓冲区BufferedReader br = new BufferedReader(new InputStreamReader(System.in));String line = null;while ((line=br.readLine())!=null){//2.封装数据byte[] bytes = line.getBytes();//地址InetAddress address =InetAddress.getByName("192.168.31.137");//参数:数据、长度、地址、端口DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,6666);//3.发送数据包ds.send(dp);}//4.关闭socket服务ds.close();}
}

在接收方方法写一个无限循环让其处于持续接收状态,发送发通过对键盘录入加回车进行消息的发送,并且两个端点都具备发送和接收功能。需要注意的是receive()会执行一个无限循环,所以receive()和send()必须位于不同线程,否则会导致无法发送消息从而也接收不到消息。

来看打印结果:
UDPSocket1

UDPSocket Receiver Start...
UDPSocket Receive:hello udp1
heelo udp2

UDPSocket2

UDPSocket2 Receiver Start...
hello udp1
UDPSocket2 Receive:hello udp2

我在UDPSocket1 的控制台中输入了:“hello udp2”、在UDPSocket2 的控制台中输入了:“hello udp1”,接收内容和发送内容完全一致,一个简单的聊天功能就实现了,希望不熟悉的朋友也可以敲一遍代码练一遍。

TCP Socket

TCP基于client-server是面向连接的可靠传输,上篇文章我们也讲解了TCP安全传输机制,可谓是相当复杂,如果需要个人对TCP协议进行封装显然大多数开发者是很难实现的,所以Java也为开发者提供了基于TCP的Socket,不同于UDP,TCP Socket分为Socket和ServerSocket对应着client和server,下面我来用代码实现一个简单的TCP通讯功能:
客户端:

//客户端
public class TCPClient {public static void main(String[] args) throws IOException {//1.创建TCP客户端Socket服务Socket client = new Socket();//2.与服务端进行连接InetSocketAddress address = new InetSocketAddress("192.168.31.137",10000);client.connect(address);//3.连接成功后获取客户端Socket输出流OutputStream outputStream = client.getOutputStream();//4.通过输出流往服务端写入数据outputStream.write("hello server".getBytes());//5.关闭流client.close();}
}

首先创建一个Socket和InetSocketAddress ,然后通过Socket的connect()方法进行连接,连接成功后可以获取到输出流,通过该输出流就可以向服务端传输数据。
服务端:

public class TCPServer {public static void main(String[] args) throws IOException {//1.创建服务端Socket并明确端口号ServerSocket serverSocket = new ServerSocket(10000);//2.获取到客户端的SocketSocket socket = serverSocket.accept();//3.通过客户端的Socket获取到输入流InputStream inputStream = socket.getInputStream();//4.通过输入流获取到客户端传递的数据BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));String line = null;while ((line = bufferedReader.readLine())!=null){System.out.println(line);}//5.关闭流socket.close();serverSocket.close();}

首先创建一个服务端Socket并明确端口号,通过accept()方法获取到链接过来的客户端Socket,从客户端Socket中获取输入流,最后由输入流读取客户端传输来的数据。

我们来看看服务端的打印结果:

hello server

成功接收到客户端发来的数据

注意点:
一个服务端是可以同时和多个客户端进行通信的,那么它是如何区分不同客户端呢?从上面代码我们可以看到,服务端首先通过accept()获取到客户端Socket,然后通过客户端的Socket获取的流进行通讯,这也让服务端得以区分每个客户端。

文件传输实例

流程:客户端上传一个文件到服务端,服务端收到文件后进行保存,保存成功后给客户端一个响应。
客户端代码

public class TCPUploadClient {public static void main(String[] args) throws IOException {//1.创建TCP客户端Socket服务Socket client = new Socket();//2.与服务端进行连接InetSocketAddress address = new InetSocketAddress("192.168.31.137",10001);client.connect(address);//3.读取客户端文件FileInputStream fis = new FileInputStream("E://girl.jpg");//4.获取输出流OutputStream outputStream = client.getOutputStream();//5.将文件写入到服务端byte[] bytes = new byte[1024];int len = 0;while ((len = fis.read(bytes))!=-1){outputStream.write(bytes,0,len);}//6.通知服务器数据写入完毕client.shutdownOutput();//7.读取服务端响应的数据InputStream inputStream = client.getInputStream();BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));String line = br.readLine();System.out.println(line);//8.关闭流inputStream.close();fis.close();client.close();}
}

创建Socket并连接,读取本地文件输入流,将文件写入到服务端,写入成功后读取服务端返回的数据。

服务端代码

public class TCPUploadServer {public static void main(String[] args) throws IOException {//1.创建客户端SocketServerSocket serverSocket = new ServerSocket(10001);//2.获取到客户端SocketSocket socket = serverSocket.accept();//3.通过客户端Socket获取到输入流InputStream is = socket.getInputStream();//4.将流以文件的形式写入到磁盘File dir = new File("F://tcp");//如果文件夹不存在就创建文件夹if(!dir.exists()){dir.mkdirs();}File file = new File(dir,"girl.jpg");FileOutputStream fos = new FileOutputStream(file);byte[] bytes = new byte[1024];int len = 0;while ((len = is.read(bytes))!=-1){fos.write(bytes,0,len);}//5.通知客户端文件保存完毕OutputStream os = socket.getOutputStream();os.write("success".getBytes());//6.关闭流fos.close();os.close();socket.close();}
}

创建Socket并获取到客户端Socket和输入流,在F盘的tcp目录下创建一个文件,将从客户端读取到的数据输出到文件中,保存成功后给客户端返回’‘success’’

这样我们就实现了一哥客户端上传文件的功能,还是比较简单的,希望大家也能够跟着代码敲一遍。

TCP Socket多线程应用

细心的同学可能已经发现,上面我们的实例中一个服务端只能接收一个客户端的一次请求,这显然是不符合实际的,那么如何使一个服务端同时服务多个客户端呢?接着撸代码

//客户端1
public class TCPClient1 {public static void main(String[] args) throws IOException {System.out.println("TCPClient1 Start...");//1.创建TCP客户端Socket服务Socket client = new Socket();//2.与服务端进行连接InetSocketAddress address = new InetSocketAddress("192.168.31.137",10004);client.connect(address);//3.连接成功后获取客户端Socket输出流OutputStream outputStream = client.getOutputStream();//4.通过输出流往服务端写入数据outputStream.write("Hello my name is Client1".getBytes());//5.告诉服务端发送完毕client.shutdownOutput();//6.读取服务端返回数据InputStream is = client.getInputStream();byte[] bytes = new byte[1024];int len = is.read(bytes);System.out.println(new String(bytes,0,len));//7.关闭流client.close();}
}//客户端2
public class TCPClient2 {public static void main(String[] args) throws IOException {System.out.println("TCPClient2 Start...");//1.创建TCP客户端Socket服务Socket client = new Socket();//2.与服务端进行连接InetSocketAddress address = new InetSocketAddress("192.168.31.137",10004);client.connect(address);//3.连接成功后获取客户端Socket输出流OutputStream outputStream = client.getOutputStream();//4.通过输出流往服务端写入数据outputStream.write("Hello my name is Client2".getBytes());//5.告诉服务端发送完毕client.shutdownOutput();//6.读取服务端返回数据InputStream is = client.getInputStream();byte[] bytes = new byte[1024];int len = is.read(bytes);System.out.println(new String(bytes,0,len));//7.关闭流client.close();}
}
//服务端
public class TCPServer {public static void main(String[] args) throws IOException {receive();}private static void receive() throws IOException {System.out.println("Server Start...");//创建服务端Socket并明确端口号ServerSocket serverSocket = new ServerSocket(10004);while (true){//获取到客户端的SocketSocket socket = serverSocket.accept();//通过客户端的Socket获取到输入流InputStream is = socket.getInputStream();//通过输入流获取到客户端传递的数据byte[] bytes = new byte[1024];int len = is.read(bytes);System.out.println(new String(bytes,0,len));//将客户端发来的数据原封不动返回OutputStream os = socket.getOutputStream();os.write(new String(bytes,0,len).getBytes());//关闭连接socket.close();}}
}

客户端1控制台

TCPClient1 Start...
Hello my name is Client1

客户端2控制台

TCPClient2 Start...
Hello my name is Client2

这样就可以实现一个服务端服务多个客户端

细心的同学可能又发现了,上面的写法是存在问题的,由于服务端始终都在主线程中处理请求,所以客户端的请求需要被服务端排队处理,举个例子:Client1对服务端进行了一次请求,服务端在响应Client1之前是不会接受其他请求的,显然这是不符合逻辑的,真正的服务器是要具备并发处理的。而多线程恰好能解决这个问题,我们来看修改之后的服务端代码

public class TCPServer {public static void main(String[] args) throws IOException {receive();}private static void receive() throws IOException {System.out.println("Server Start...");//创建服务端Socket并明确端口号ServerSocket serverSocket = new ServerSocket(10004);while (true){//获取到客户端的Socketfinal Socket socket = serverSocket.accept();//通过线程执行客户端请求new Thread(new Runnable() {@Overridepublic void run() {try {//通过客户端的Socket获取到输入流InputStream is = socket.getInputStream();//通过输入流获取到客户端传递的数据byte[] bytes = new byte[1024];int len = is.read(bytes);System.out.println(new String(bytes,0,len));//将客户端发来的数据原封不动返回OutputStream os = socket.getOutputStream();os.write(new String(bytes,0,len).getBytes());//关闭连接socket.close();} catch (IOException e) {e.printStackTrace();}}}).start();}}
}

运行效果适合加线程之前是一样的,但这种方式效率更高。

本篇文章叙述了基于UDP和TCP的Socket,UDP是无连接的,所以UDP Socket在发送数据的时候只需要目标IP和端口即可发送。TCP是面向连接的并且是基于client-server模式,在传输数据前需要进行连接,可以通过多线程技术实现并发处理客户端请求。本篇文章内容还是比较简单的,希望大家能把文章中代码自己敲一遍,掌握Socket的同时也能让你自己UDP和TCP的理解更加深刻。

什么是socket通信相关推荐

  1. python 网络编程之Socket通信案例消息发送与接收

    背景 网络编程是python编程中的一项基本技术.本文将实现一个简单的Socket通信案例消息发送与接收 正文 在python中的socket编程的大致流程图如上所示 我们来首先编写客户端的代码: # ...

  2. C# Socket系列三 socket通信的封包和拆包

    通过系列二 我们已经实现了socket的简单通信 接下来我们测试一下,在时间应用的场景下,我们会快速且大量的传输数据的情况! 1 class Program 2 { 3 static void Mai ...

  3. flex java socket通信

    引用:http://developer.51cto.com/art/201003/189791.htm Java socket通信如何进行相关问题的解答呢?还是需要我们不断的学习,在学习的过程中会遇到 ...

  4. Socket通信之操作系统的字节序和位数

    关于Socket通信过程中字节序 在网络编程里,网络字节序是big-endian的,而大部分的PC的系统都是X86处理器系列,X86采用的是little-endian,所以需要将网络数据流转换成本地数 ...

  5. 1.Socket通信

    本博客部分内容参考教程来自C语言中文网. 进入socket通信首先要了解两个概念,第一:服务器端,第二:客户端.(区别是两者的服务对象不同.服务器端是为客户端服务的,客户端就是为真正的"客户 ...

  6. java iso8583 socket 服务_JAVA客户端amp;服务器的socket通信

    JAVA客户端&服务器的socket通信 socket是两台主机之间的一个连接通道,它可以完成七个基本操作: 发送远程机器 发送数据 接收数据 关闭连接 绑定端口 监听入站数据 再绑定端口上接 ...

  7. 手把手教你 Socket 通信(TCP/IP)

    本文将给出完整 Socket 通信代码,在 eclipse 中亲测有效.在Android Studio中用Java开发也是一样的,只是把代码和控件搭配一下,注册监听就好. 网络上的两个程序通过一个双向 ...

  8. protobuf和socket通信简单实例

    protobuf和socket通信简单实例   protobuf是 Google 公司内部的混合语言数据标准,可以用来定义通信的协议,由于其有序列化和反序列化的操作,减小了存储或通信的数据量,从而达到 ...

  9. [其他]JAVA与C#的Socket通信

    在日常的开发中,不同的传感器支持的开发语言常常是不同的.例如Kinect一般是用C++开发的,Leapmotion用JAVA开发比较多. 去年暑假(17年暑假)做的一个项目是:用Leapmotion捕 ...

  10. Android之Socket通信、List加载更多、Spinner下拉列表

    Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是"请求-响应方式",即在请求时建立连接通道,当客户端向服 ...

最新文章

  1. 设计模式笔记(18)---迭代器模式(行为型)
  2. 用一句JQuery代码实现表格的简单筛选
  3. STM32的时钟配置随笔
  4. SCOUNIX第十二讲:使用TCP/IP
  5. Intel Realsense D435运行报错 RuntimeError: Camera not connected! dev.hardware_reset()函数需加睡眠sleep()
  6. vsftpd服务的搭建
  7. loadrunner监控linux性能指标,使用LoadRunner监控Linux系统性能.doc
  8. stat函数_数据分析工具入门 掌握这些Excel函数就够了
  9. 大众CEO称市场有足够资金,支持建设6座大型电池工厂
  10. 十年了,斯坦福和CMU的这场对决,开启了无人车时代
  11. python零基础能学吗-初学者必知:零基础学习Python真的能学会吗?
  12. 回顾︱DeepAR 算法实现更精确的时间序列预测(二)
  13. kafka查看消费位置
  14. java jquery用的多吗_[Java教程]如果不用jQuery,Ajax你还能写出多少?
  15. Python 电子书下载列表
  16. 1.1 半导体基础知识
  17. 刷榜中ASO优化中下载量与评论之间的对应比
  18. ThinkPHP带表情无限级评论回复
  19. 《具体数学》部分习题解答1
  20. app常见的 闪退及闪退的原因

热门文章

  1. 初识二维码 第十八讲 编码转换
  2. nmap的下载与安装
  3. cygwin使用apt-cyg
  4. Golang + HTML5 实现多文件上传
  5. 无WiFi 条件下如何使用Xshell 串口访问树莓派终端
  6. 如何编制试算平衡表_试算平衡表的编制步骤是怎样的?
  7. react-native获取农历日期和二十四节气
  8. 获取jqGrid中每行的子元素td并修改其属性
  9. CVPR21-无监督异常检测《CutPaste:Self-Supervised Learning for Anomaly Detection and Localization》
  10. 超级计算机作文230字,我想养小兔子二年级作文230字