网络编程 - Socket编程

java socket编程
Java Socket编程----通信是这样炼成的

前言:socket做了什么

从一个概况的层面来说,Socket是网络通信的端点,可以把一个Socket绑定在一个ip+端口上标识一个进程
当应用进程想通过Socket传输数据,实际上是把Socket绑定在了网卡驱动程序上,这样网卡就知道从这个ip+端口进来的数据都要给我这个应用进程
在这里插入图片描述
在这里插入图片描述

针对网络通信的不同层次,Java提供了不同的API,其提供的网络功能有四大类

1. 关于IP地址 – InetAddress

用于标识网络上的硬件资源,标识互联网协议(IP)地址。

//获取本机的InetAddress实例
InetAddress address =InetAddress.getLocalHost();//返回本机

//获取其他主机的InetAddress实例
InetAddress address2 =InetAddress.getByName("其他主机名");//根据域名得到InetAddress对象
InetAddress address3 =InetAddress.getByName("IP地址");//根据IP地址得到InetAddress对象

address.getHostName();//获取计算机名
address.getHostAddress();//获取IP地址
byte[] bytes = address.getAddress();//获取字节数组形式的IP地址,以点分隔的四部分

2. 关于IP+端口 – InetSocketAddress

此类实现 IP 套接字地址(IP 地址 + 端口号)。它还可以是一个对(主机名 + 端口号),在此情况下,将尝试解析主机名。如果解析失败,则该地址将被视为未解析地址,但是其在某些情形下仍然可以使用,比如通过代理连接

//获取本机的InetAddress实例
InetSocketAddress address =new InetSocketAddress("127.0.0.1",8080);//返回本机
InetSocketAddress address =new InetSocketAddress("localhost",8080);//返回本机
address.getHostName();//获取计算机名
address.getAddress();//获取IP地址
address.getPort();//获取端口号

3. URL类

URL:统一资源定位符,表示是一个地址,包括协议,域名,端口号,资源文件名 http://www.google.com:80/index.html

URI:“A Uniform Resource Identifier (URI) 是一个紧凑的字符串用来标示抽象或物理资源。”

“A URI 可以进一步被分为定位符、名字或两者都是. 术语“Uniform Resource Locator” (URL) 是URI的子集, 除了确定一个资源,还提供一种定位该资源的主要访问机制(如其网络“位置”)

URL是URI的一种,URI是URL的抽象,URL具体化了URI的某一部分,也就是说URL不仅表示了要请求资源的名称,而且确定了要访问资源的地址

//创建一个URL的实例
URL url=new URL("http://www.baidu.com/index.html?username=tom#test");
//或者
//URL baidu =new URL("http://www.baidu.com");
//URL url =new URL(baidu,"/index.html?username=tom#test");//?表示参数,#表示锚点
url.getProtocol();//获取协议
url.getHost();//获取主机
url.getPort();//如果没有指定端口号,根据协议不同使用默认端口。此时getPort()方法的返回值为 -1
url.getPath();//获取文件路径
url.getFile();//文件名,包括文件路径+参数
url.getRef();//相对路径,就是锚点,即#号后面的内容
url.getQuery();//查询字符串,即参数

3.1 使用URL读取网页内容

通过URL对象的openStream()方法可以得到指定资源的输入流,通过流能够读取或访问网页上的资源
其实和也就是爬虫的基本原理
① 获取URL
②下载资源
③ 对资源分析(正则表达式)
④数据抽取存储

//使用URL读取网页内容
//创建一个URL实例
URL url =new URL("http://www.baidu.com");
InputStream is = url.openStream();//通过openStream方法获取资源的字节输入流
InputStreamReader isr =new InputStreamReader(is,"UTF-8");//将字节输入流转换为字符输入流,如果不指定编码,中文可能会出现乱码
BufferedReader br =new BufferedReader(isr);//为字符输入流添加缓冲,提高读取效率
String data = br.readLine();//读取数据
while(data!=null){
System.out.println(data);//输出数据
data = br.readerLine();
}
br.close();
isr.colose();
is.close();

可以使用HttpURLConnection模拟浏览器访问
在这里插入图片描述

4. TCP编程

tcp是传输层协议,其上层的应用有Http等
TCP协议是面向连接的、可靠的、有序的、以字节流的方式发送数据,通过三次握手方式建立连接,形成传输数据的通道,在连接中进行大量数据的传输,效率会稍低

4.1 Java中基于TCP协议实现网络通信的类

我们开发的网络应用位于应用层,而TCP, UDP是传输层协议,那么在应用层怎么使用传输层的协议呢,是通过套接字来进行分离的,套接字就是传输层为应用层开的小口,应用程序通过这个小口向远程发送数据,或者接收远程发来的数据

TCP以IO流来交流

1. Socket通信的步骤
① 创建ServerSocketSocket
② 打开连接到Socket的输入/输出流
③ 按照协议对Socket进行读/写操作
④ 关闭输入输出流、关闭Socket
在这里插入图片描述

2. 服务器端的ServerSocket
① 创建ServerSocket对象,绑定监听端口
② 通过accept()方法监听客户端请求
③ 连接建立后,通过输入流读取客户端发送的请求信息
④ 通过输出流向客户端发送信息
⑤ 关闭相关资源

   import java.io.*;
  import java.net.*;
  import java.applet.Applet;
  public class TalkServer{
    public static void main(String args[]) {
      try{
        ServerSocket server=null;
        try{
          server=new ServerSocket(4700);
        //创建一个ServerSocket在端口4700监听客户请求
        }catch(Exception e) {
          System.out.println("can not listen to:"+e);
        //出错,打印出错信息
        }
        Socket socket=null;
        try{
          socket=server.accept();
          //使用accept()阻塞等待客户请求,有客户
          //请求到来则产生一个Socket对象,并继续执行
        }catch(Exception e) {
          System.out.println("Error."+e);
          //出错,打印出错信息
        }
        String line;
        BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));
         //由Socket对象得到输入流,并构造相应的BufferedReader对象
        PrintWriter os=new PrintWriter(socket.getOutputStream());
         //由Socket对象得到输出流,并构造PrintWriter对象
        BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));
         //由系统标准输入设备构造BufferedReader对象
        System.out.println("Client:"+is.readLine());
        //在标准输出上打印从客户端读入的字符串
        line=sin.readLine();
        //从标准输入读入一字符串
        while(!line.equals("bye")){
        //如果该字符串为 "bye",则停止循环
          os.println(line);
          //向客户端输出该字符串
          os.flush();
          //刷新输出流,使Client马上收到该字符串
          System.out.println("Server:"+line);
          //在系统标准输出上打印读入的字符串
          System.out.println("Client:"+is.readLine());
          //从Client读入一字符串,并打印到标准输出上
          line=sin.readLine();
          //从系统标准输入读入一字符串
        }  //继续循环
        os.close(); //关闭Socket输出流
        is.close(); //关闭Socket输入流
        socket.close(); //关闭Socket
        server.close(); //关闭ServerSocket
      }catch(Exception e){
        System.out.println("Error:"+e);
        //出错,打印出错信息
      }
    }
  }

3. 客户端的Socket
① 创建Socket对象,指明需要连接的服务器的地址和端口号
② 连接建立后,通过输出流想服务器端发送请求信息
③ 通过输入流获取服务器响应的信息
④ 关闭响应资源

   import java.io.*;
  import java.net.*;
  public class TalkClient {
    public static void main(String args[]) {
      try{
        Socket socket=new Socket("127.0.0.1",4700);
        //向本机的4700端口发出客户请求
        BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));
        //由系统标准输入设备构造BufferedReader对象
        PrintWriter os=new PrintWriter(socket.getOutputStream());
        //由Socket对象得到输出流,并构造PrintWriter对象
        BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));
        //由Socket对象得到输入流,并构造相应的BufferedReader对象
        String readline;
        readline=sin.readLine(); //从系统标准输入读入一字符串
        while(!readline.equals("bye")){
        //若从标准输入读入的字符串为 "bye"则停止循环
           os.println(readline);
          //将从系统标准输入读入的字符串输出到Server
          os.flush();
          //刷新输出流,使Server马上收到该字符串
          System.out.println("Client:"+readline);
          //在系统标准输出上打印读入的字符串
          System.out.println("Server:"+is.readLine());
          //从Server读入一字符串,并打印到标准输出上
          readline=sin.readLine(); //从系统标准输入读入一字符串
        } //继续循环
        os.close(); //关闭Socket输出流
        is.close(); //关闭Socket输入流
        socket.close(); //关闭Socket
      }catch(Exception e) {
        System.out.println("Error"+e); //出错,则打印出错信息
      }
  }
}

4.2 应用多线程实现服务器与多客户端之间的通信

① 服务器端创建ServerSocket,循环调用accept()等待客户端连接
② 客户端创建一个socket并请求和服务器端连接
③ 服务器端接受客户端请求,创建socket与该客户建立专线连接
④ 建立连接的两个socket在一个单独的线程上对话
⑤ 服务器端继续等待新的连接

//服务器线程处理
//和本线程相关的socket
Socket socket =null;
//
public serverThread(Socket socket){
this.socket = socket;
}

publicvoid run(){
//服务器处理代码
}

//============================================
//服务器代码
ServerSocket serverSocket =new ServerSocket(10086);
Socket socket =null;
int count =0;//记录客户端的数量
while(true){
socket = serverScoket.accept();
ServerThread serverThread =newServerThread(socket);
 serverThread.start();
 count++;
System.out.println("客户端连接的数量:"+count);
}

5. UDP编程

UDP协议(用户数据报协议)是无连接的、不可靠的、无序的,速度快
进行数据传输时,首先将要传输的数据定义成数据报(Datagram),大小限制在64k,在数据报中指明数据索要达到的Socket(主机地址和端口号),然后再将数据报发送出去

由于是基于数据报的,一切以包裹为中心,在传输的时候不使用IO流而是将每个数据发送单元统一封装成数据包的方式,发送方将数据包发送到网络中,数据包在网络中寻找他的目的地

  • DatagramPacket类: 表示数据报包
  • DatagramSocket类: 进行端到端通信的类

5.1 服务器端实现步骤

① 创建DatagramSocket,指定自己的端口号,创建接收端,被人发要往这个上面发
② 准备容器 封装成DatagramPacket包裹
③ 阻塞式接受客户端发送的数据信息
④ 读取数据

//服务器端,实现基于UDP的用户登录
//1. 创建服务器端DatagramSocket,指定端口
DatagramSocket socket =new datagramSocket(10010);
//2. 创建数据报,用于接受客户端发送的数据
byte[] data =new byte[1024];//1k
//2. 准备容器 封装成DatagramPacket包裹
DatagramPacket packet =newDatagramPacket(data,data.length);
//3. 接受客户端发送的数据
socket.receive(packet);//此方法在接受数据报之前会一致阻塞
//4. 读取数据
String info =new String(data,0,data.length);
System.out.println("我是服务器,客户端告诉我"+info);


//=========================================================
//向客户端响应数据
//1、定义客户端的地址、端口号、数据
InetAddress address = packet.getAddress();
int port = packet.getPort();
byte[] data2 = "欢迎您!".geyBytes();
//发生方需要指定发送地址
//2、创建数据报,包含响应的数据信息
DatagramPacket packet2 = new DatagramPacket(data2,data2.length,address,port);
//3、响应客户端
socket.send(packet2);
//4、关闭资源
socket.close();

5.2 客户端实现步骤

① 定义发送信息
② 创建DatagramPacket,封装字节数组,包含将要发送的信息,指定对方的ip和端口
③ 创建DatagramSocket,创建发送端
④ 发送数据

//客户端
//1、定义服务器的地址、端口号、数据
InetAddress address =InetAddress.getByName("localhost");
int port =10010;
byte[] data ="用户名:admin;密码:123".getBytes();//数据一定要转为字符数组再打包
//2、创建数据报,包含发送的数据信息,要发送的地址
DatagramPacket packet = new DatagramPacket(data,data.length,address,port);
//3、创建DatagramSocket对象
DatagramSocket socket =new DatagramSocket();
//4、向服务器发送数据
socket.send(packet);


//接受服务器端响应数据
//======================================
//1、创建数据报,用于接受服务器端响应数据
byte[] data2 = new byte[1024];
DatagramPacket packet2 = new DatagramPacket(data2,data2.length);
//2、接受服务器响应的数据
socket.receive(packet2);
String raply = new String(data2,0,packet2.getLenth());
System.out.println("我是客户端,服务器说:"+reply);
//4、关闭资源
socket.close();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值