java学习笔记——socket编程
来源:互联网 发布:淘宝如何快速打造爆款 编辑:程序博客网 时间:2024/06/06 04:22
实现网络编程
要用java编写一段代码用来通信的话,需要用到些什么,如何实现?
这次学习了一个socket编程(也称网络编程,套接字编程),用来解决上述问题
网络编程三要素
我们与其他人交流对话,首先我们要确定要对话的对象,并且以恰当的途径传送给他,网络编程也是如此。在网络编程中,将其总结出几个要点,如果不能满足这几个要点,则不能正确的将想要表达的信息传送给目标计算机。
1. ip地址
ip地址代表的是计算机的地址,处以同一网络环境下,计算机可以通过ip地址来确定其他计算机的地址,在传送数据的时候,也是向相应的ip地址传输。
查询ip地址的时候可以使用命令指示符ipconfig来获得自己的ip地址
2. 端口
当数据到达计算机之后,得分发到需要这个数据的应用上,为了分辨应用是否需要这个数据,需要端口号来实现,应用开启了数据包所表示的端口,计算机才会把数据传送到该应用中。有效端口有:0~65535,其中0~1024系统使用或保留端口,我们一般使用1025~65535的端口,以防止和系统端口冲突
3. 协议
协议相当于是数据传输用的语言,如果数据包说的是一门“外语”,我们就不能很好的理解这段数据所表达的意思
我们这里只说最常用的udp和tcp协议
java中传输UDP协议的包
UDP协议的特性
- 把数据打成一个数据包 , 不需要建立连接
- 数据包的大小有限制不能超过64k
- 因为无连接,所以属于不可靠协议(可能丢失数据)
- 因为无连接 ,所以效率高
UDP协议最重要的特征就是不需要建立连接,发送端随时都可以发送数据给目标ip,可以节省创建连接的时间,但是目标ip也可能没有打算接受UDP协议的包,导致数据传送过去并没有被接受。
我们在发送端要做的事情就是创建发送数据包的socket对象,将数据打包,发送过去就行;在接受端也只用创建接收数据包的socket对象,获取数据即可。
需要用到的ip地址,java使用InetAddress类来封装IP地址对象
这个类私有化了构造方法,只能通过类方法来创建对象
static InetAddress getByName(String host)
在给定主机名的情况下确定主机的 IP 地址。
–host内输入主机名或ip地址就可以构造出该计算机的Inetaddress对象
发送端
- 在发送端建立一个socket对象,这里使用DatagramSocket类
- 再建立一个数据包对象DatagramPacket(buf, length, address, port),buf是要传送的数据转化的byte[]对象,length是要传送的数据长度,address接目标Inetaddress对象,port设置为端口
- 调用DatagramSocket的send(DatagramPacket p) 方法来发送数据包p
- 释放资源
public class UdpClient { public static void main(String[] args) throws Exception { //1.创建udp协议发送端的socket对象 //public DatagramSocket() throws SocketException DatagramSocket ds = new DatagramSocket(); byte[] buf = "hello".getBytes(); int length = buf.length; InetAddress address = InetAddress.getByName("192.168.20.254"); int port = 8888; //2.创建数据包 //public DatagramPacket(byte[] buf, int length,InetAddress address,int port) DatagramPacket dp = new DatagramPacket(buf, length, address, port); //发送数据 ds.send(dp); //释放资源 ds.close(); }}
接收端
- 建立socket对象,这里也用DatagramSocket,但是要指定接受包所设定的端口,
- 创建新的包对象DatagramPacket(buf, length)来接受传送过来的数据
- 调用socket对象的receive(DatagramPacket p)
- 解析数据包——
byte[] getData()
返回数据缓冲区。
int getLength()
返回将要发送或接收到的数据的长度。 - 释放资源
public class UdpServer { public static void main(String[] args) throws Exception { //创建接收端的socket对象 DatagramSocket ds = new DatagramSocket(8888); //创建一个数据包,用来接收来自发送端的数据,是一个空的数据包 byte[] buf = new byte[1024]; int length = buf.length; DatagramPacket dp = new DatagramPacket(buf, length); //接受来自发送端的数据 //public void receive(DatagramPacket p)throws IOException //程序在这里接收到来自发送端的数据之前一直处于阻塞状态 ds.receive(dp); //解析一下数据包中的数据 //public byte[] getData()返回数据缓冲区 byte[] data = dp.getData(); //public int getLength()返回将要发送或接收到的数据的长度 int len = dp.getLength(); System.out.println(new String(data,0,len)); //释放资源 ds.close(); }}
java中传输TCP协议的数据包
TCP的特性
- 需要建立连接,形成连接通道
- 数据可以使用连接通道直接进行传输,无大小限制
- 因为有链接,所以属于可靠协议
- 因为有链接,所以效率低
TCP是先建立连接,再进行通讯的,所以必须要接收端准备好了接收你的数据,发送端才能发送,接收端和发送端实现了连接之后,可以随意的发送任意大小的数据
这里的socket对象直接使用socket类
传输数据时,直接使用输入输出流来写入和读取数据
发送端
- 建立socket对象Socket(InetAddress address, int port)
- 使用getOutputStream()来获取此套接字的输出流,向这个输出流写入数据时,直接可以被读取出来
- 释放资源
public class TcpClient { public static void main(String[] args) throws Exception { //创建tcp协议发送端的socket对象 //public Socket(String host,int port) Socket sk = new Socket("192.168.20.254", 10086); //2.public OutputStream getOutputStream()throws IOException //从通道中获取输出流对象 OutputStream os = sk.getOutputStream(); //3.给通道中写数据 os.write("hello".getBytes()); //4.释放资源 sk.close(); }}
接收端
1 . 先创建一个socket服务器对象ServerSocket并指定端口号
2. 调用ServerSocket的 accept() 方法,侦听并接受到此套接字的连接,并获取到发送端的socket对象
3. 调出socket对象的输入流,读取socket对象的数据
4. 释放资源
public class TcpServer { public static void main(String[] args) throws Exception { //创建服务器端的socket对象 ServerSocket ss = new ServerSocket(2000); //监听来自于客户端的连接 Socket sk = ss.accept(); //创建BufferedReader一次读取一行数据 BufferedReader br = new BufferedReader(new InputStreamReader(sk.getInputStream())); String line; while ((line=br.readLine())!=null) { System.out.println(line); } //释放资源 br.close(); sk.close(); }}
通过TCP协议来传输文本文件并用多线程实现接收多组数据
在实际情况中,会比上面演示的TCP传输复杂很多,针对不同的情况,要对上面的代码做出不同的修改,下面演示一个使用TCP协议来传输文本文件并用多线程实现接收多组数据的实例
- 编写一个命名类,使用UUID类来产生随机的字符串,以此来命名写出文件,保证了文件名不会重复
- 编写一个实现runnable接口的接收端功能类,这样接收端只要开启多个线程并调用接收端功能类的run()方法就可以实现接收多组数据
3.编写一个接收端程序,调用接收端功能类 - 编写读取文本的发送端程序
命名类
使用UUID类下的静态方法static UUID randomUUID() 来生成一个随机值的UUID对象,将这个对象转化为字符串,产生的字符串会是用‘-’连接的一些随机字母和数字,我们通过String类的replace()方法将‘-’去掉,并在结尾加上‘.txt’的后缀
public class UUIDUtils { @Test public static String getFileName(){ String fileName = UUID.randomUUID().toString(); fileName = fileName.replaceAll("-", "")+".txt"; return fileName; }}
接收端功能类
- 通过构造方法传入接到的socket对象,通过socket对象调取的字节输入流转化为高效字符输入流
- 构造一个高效字符输出流,输出到的文件名采用命名类给出的随机文件名
- 建立循环,输入流每读取一行数据,输出流就将其写进文件中并换行
- 释放资源
——注意抓一下异常
public class ServerThread implements Runnable{ Socket sk; public ServerThread(Socket sk){ this.sk = sk; } @Override public void run() { try { //创建BufferedReader一次读取一行数据 BufferedReader br = new BufferedReader(new InputStreamReader(sk.getInputStream())); BufferedWriter bw = new BufferedWriter(new FileWriter(UUIDUtils.getFileName())); String line; while ((line=br.readLine())!=null) { bw.write(line); bw.newLine(); bw.flush(); //System.out.println(line); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
接收端
- 建立一个ServerSocket对象用来接收传送过来的Socket对象
- 建立循环接受Socket对象,创建进程调用run方法
public class TcpServer { public static void main(String[] args) throws Exception { //创建服务器端的socket对象 ServerSocket ss = new ServerSocket(2000); while (true) { //蒋婷来自于客户端的连接 Socket sk = ss.accept(); //启动一个子线程,去执行复制文件的动作 new Thread(new ServerThread(sk)).start(); } }}
发送端
发送端和前面介绍的例子区别不大,但是要读取文件,就要以socket对象创建一个高效字符输入流,以此来用行作为单位发送数据,这里我们为了演示只发送同一个文件的内容
public class TcpClient { public static void main(String[] args) throws Exception { //创建socket对象 Socket sk = new Socket("192.168.20.254", 2000); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(sk.getOutputStream())); //读取文本一次读取一行 BufferedReader br = new BufferedReader(new FileReader("InetAddressDemo.java")); String line; while ((line=br.readLine())!=null) { //line就是我读取到的数据,我需要将这个数据写入通道,一次写一行 bw.write(line); bw.newLine(); bw.flush(); } //释放资源 br.close(); bw.close(); sk.close(); }}
socket编程其实就是io流的一个用法。数据是在发送端和接收端的socket之间传输,从根本上,还是用的io流那一套,只是从操作文件对象,变成了操作socket对象。
- java学习笔记——socket编程
- JAVA socket编程学习笔记
- JAVA学习笔记- Socket编程
- java socket编程学习笔记
- java socket 编程学习笔记
- java Socket编程学习笔记 01——基于TCP协议的Socket编程
- JAVA学习笔记(五十九)- Socket编程
- JAVA Socket 编程学习笔记(一)
- JAVA Socket 编程学习笔记(一)
- Java学习笔记--网络编程Socket
- 【Java学习笔记】23.网络编程--Socket
- socket编程学习笔记
- socket 编程学习笔记
- socket编程学习笔记
- JAVA学习笔记Day24——javaTCP UDP网络编程Socket总结
- Java Socket编程笔记
- Android学习笔记17——TCP/IP socket编程
- Android学习笔记17——TCP/IP socket编程
- golang 输出gif图片
- PHP 编程中 10 个最常见的错误,你犯过几个?
- WedView的加载网页与进度条
- tomcat运行报错Failed to start component [StandardEngine[Catalina].StandardHost[localhost].
- java把String字符串第一个汉字放到末尾
- java学习笔记——socket编程
- SpringBoot配置属性之Migration
- 计算机发展简介
- 自己看
- 关于openstack中普通用户如何获取权限查询集群信息,创建模版flavor
- 为GUI表格添加合计行,代码实现,常用于EditUI
- Android 获取assets的绝对路径
- Python 配置处理类(ini文件)
- python005 -- from inport 作用