文档章节

TCP/UDP套接字 java socket编程实例

o
 osc_odyg6b92
发布于 2018/07/13 11:41
字数 2200
阅读 4
收藏 0

「深度学习福利」大神带你进阶工程师,立即查看>>>

网络协议七层结构:

 

什么是Socket?

  socket(套接字)是两个程序之间通过双向信道进行数据交换的端,可以理解为接口。使用socket编程也称为网络编程,socket只是接口并不是网络通信协议。

HTTP协议和Socket的区别

  http协议是应用层,其模式是请求-应答,客户端发送请求,服务器端进行响应。传输的数据是原始格式的数据,eg :json、xml、text等数据格式。

  socket不是协议是接口,socket提供TCP/UDP socket 的实例,供java 或者其他语言操作数据的传输,socket是对传输层(TCP/UPD协议)的封装。

Socket通信分为两种

  TCP Socket :使用流传输,提供inputStream 和 outputStream 方法对数据进行流操作。要理解TCP套接字首先要对TCP协议有所理解。

    1)TCP协议是传输层的协议,他的下一层是IP协议(网络层),IP协议在网络数据传输是通过ip寻址,将源地址和目的地址进行连接。TCP协议是在IP协议上多加一层端口寻址,光只通过IP寻址只能定位到主机,tcp通过端口找到对应的应用程序。

    2)TCP 建立连接需要三次握手,将源应用程序和目的应用程序之间搭建一个连接,所以源应用和目的应用程序之间必须是one by one。IP 协议只管数据的传输,不保证数据是否丢失,重复传,顺序是否正确,TCP会对这些问题做一些补偿机制,丢失数据重传,用队列保证数据的顺序。

    3) TCP 缺点:因为每个客户端和服务器端传输数据都要建立连接,三次握手是不传输数据并且有耗时,当有大量短连接的时候并且对数据的正确性要求不高的时候,将会占用带宽。

  UDP Socket:使用数据报文进行传输,创建UDP socket 发送和接收数据报文。

    1)UDP协议同TCP协议一样都是应用层协议,也是通过端口寻址,找到对应的应用程序。

    2)UDP传输数据报文不需要和目的应用程序建立连接,他在数据报文中指定目的主机和目的端口号,发送出的数据自动寻址到对应的主机和端口号。因为不用和目的主机建立连接,所以一个源应用程序可以以广播的形式将数据报文传输给多主机。因为不用建立连接,耗时和带宽占用量都比TCP协议更优秀

    3)UDP缺点:数据有可能丢失,丢失的数据不会重传

java socket 实例

  TCP Socket client

 

package socket.transmission.tcp;


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

//TCP 套接字 客户端负责发送请求
public class TcpClient {
    private static  final  int BUF_SIZE=32;
    /**
     * TCP客户端发送一个请求要有三个步骤:
     *  1.创建一个socket的实例,创建一个指向server主机ip和端口号的TCP连接
     *  2.通过套接字的输入和输出流进行通信
     *  3.使用socket close关闭
     */
    public static void main(String[] args){
      String ip="192.168.197.1";
        int port=8080;
        try {
            // 创建一个socket实例
            Socket socket=new Socket(ip,port); // 1 设置TCP SOCKET,初始化目的主机ip和端口号,建立和目的主机的连接,若目的主机没有开启服务,则会弹出server refused
            System.out.println("创建一个socket连接");
            InputStream inputStream=socket.getInputStream();  // 2 获取回馈服务器的输入流
            OutputStream outputStream=socket.getOutputStream(); // 3 将要传输的数据数据写入到输出流中,传输给目的主机
            //向socket中写入数据
            outputStream.write("this is a word".getBytes());  // 4 传输数据到目的主机
            int totalByrecive=0;  //到目前为止接收到的数据
            byte[] readBuff=new byte[BUF_SIZE];
            int lastReadByte;  //最后接收的字节
            System.out.println("从服务器中接收的数据:");
            int receiveMsgSize;
            while ((receiveMsgSize=inputStream.read(readBuff))!=-1){   // 5.从回馈服务器中获取数据,
                System.out.println(new String(readBuff));
            }
             socket.close();  //关闭
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

 

tcp sokect server

package socket.transmission.tcp;

//TCP 服务器端进行接收请求

import sun.java2d.pipe.OutlineTextRenderer;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;

/**
 * TCP服务器对客户端发送的请求会进行以下处理
 *  1.创建serverSocket实例并且指定本机端口,功能:监听指定端口发送过来的连接
 *  2.重复执行:
 *      1).调用的serverSocket 的accept() 监听客户端发送过来的请求,并创建socket
 *      2).使用socket的inputStream 和  outputStream 进行通讯
 *      3).通信完使用socket.close() 方法将连接关闭
 */
public class TcpServer {

    private static  final  int BUF_SIZE=32;

    public static void main(String[] args){
        int port=8080;
        Socket socket = null;
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            ServerSocket serverSocket=new ServerSocket(port);//创建一个socket实例用于监听客户端发送的连接,指定本服务器的端口号
            System.out.println("创建serverSocket 实例");
            int reviceMsgSize;   // 接收msg的大小
            byte[] receiveBuf=new byte[BUF_SIZE];  //创建一个信息接收的缓冲区
                System.out.println("开始处理接收的数据");
                while (true) {
                    socket = serverSocket.accept();  //接收客户端的连接,每接收一个数据都会创建一个连接,当没有数据的接收的时候会阻塞
                    SocketAddress socketAddress = socket.getRemoteSocketAddress(); //
                    System.out.println("访问的地址:" + socketAddress);
                    inputStream = socket.getInputStream();
                    outputStream = socket.getOutputStream();
                    while ((reviceMsgSize = inputStream.read(receiveBuf)) != -1) {
                        System.out.println(new String(receiveBuf));
                        outputStream.write("aaaaa".getBytes(), 0, 4);
                    }
                    outputStream.flush();
                    socket.close();
                }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
                try {
                    if(socket!=null){
                        socket.close();
                    }
                    if(inputStream!=null){
                        inputStream.close();
                    }
                    if(outputStream!=null){
                        outputStream.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
    }


}

 UDP Socket client

package socket.transmission.udp;


import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.*;

//UDP 套接字传输的是数据报文

/**
 * UDP 客户端发送数据报文的步骤:
 *  1.创建UPD 套接字 DataGramSocket ,使用UDP协议通信是不需要和服务器端创建的连接的,UPD协议只是在IP协议上
 *    多加了一层端口寻址,设置超时
 *  2.创建发送的数据报文实例DataGramPacket,若是单播的则要指明目的端的ip地址和port,IP地址通过创建InetAddress 的实例
 *  3.创建接收数据报文实例DataGramPacket ,指定接收数据的缓冲区
 *  4.调用socket的send方法将数据报文发送出去
 *  5.循环接收数据报文,当数据报文丢失的时候,发起重试。否则设置响应标志位true,将数据打印
 */
public class UdpClient {
    /**
     * 当客户端发送给server端信息,收到回馈信息的时候,通过read读取数据,当没有数据返回(数据丢失)
     * read 方法会发生阻塞,若没有设置超时重发,则程序会一直阻塞
     */
    private static final int TIME_OUT=2000;  //设置超时重发时间

    private static final int MAX_RENTRY=3;  // 设置最大重试次数

    public  static void main(String[] args) throws IOException {
        try {
            int serverPort=8080; // 指定
            byte[] sendMsg="this is a test".getBytes();
            DatagramSocket socket=new DatagramSocket(); //创建一个数据报文
            socket.setSoTimeout(TIME_OUT);  //设置read阻塞超时时间
            byte[] ipByte={10,1,1,100};
            /**
             * "10.1.1.100".getbytes()的方式不能正确的创建server端,调用InetAddress.getByAddress() 方法将会做两个长度判断,IPV4 的入参长度要==4
             *  IPV6 的长度要== 16 而通过10.1.1.100 getbytes的方式获取的长度是10 抛出违法的长度
             */
            InetAddress inetAddress= InetAddress.getByAddress(ipByte);  //创建server主机的ip地址
            DatagramPacket sendPacket=new DatagramPacket(sendMsg,sendMsg.length,inetAddress,8080);  //发送的数据报文
            DatagramPacket receivePacket=new DatagramPacket(new byte[sendMsg.length],sendMsg.length);  //接收的数据报文
            int tryTimes=0;  //数据报文可能丢失,设置重试计数器
            Boolean receiveResponse=false;
            socket.send(sendPacket);  //将数据报文发送出去
            do{
                try {
                    socket.receive(receivePacket);   //尝试去循环接收数据报文
                    if (!receivePacket.getAddress().equals(inetAddress)) { //检查回馈过来的数据报文
                        throw new IOException("未知的Server端数据报文");
                    }
                    receiveResponse=true;
                }catch (InterruptedIOException e){ //数据报文中断异常
                    tryTimes++;
                    System.out.println("超时还有"+(MAX_RENTRY-tryTimes)+"次重试机会");
                }
            }while(!receiveResponse&&(tryTimes<MAX_RENTRY));
            if(receiveResponse){
                System.out.println("从服务器端获取的数据:"+new String(receivePacket.getData()));
            }else{
                System.out.println("没有获取到数据");
            }
            socket.close(); //关闭套接字
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }
}

UPD Soceket server

package socket.transmission.udp;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.*;

//UDP 套接字接收客户端的数据报文
public class UdpServer {
    private static final int ECHO_MAX=255;  //设置缓冲区的长度

    public static void main(String[] args)  {
        try {
            DatagramSocket datagramSocket=new DatagramSocket(8080);
            DatagramPacket reveiveMsg=new DatagramPacket(new byte[ECHO_MAX],ECHO_MAX);
            while(true){
                    datagramSocket.receive(reveiveMsg);
                System.out.println("从客户端接收的来数据:"+new String(reveiveMsg.getData()));
                //在服务器端将发送的信息修改
                byte[] newData="啦啦啦啦".getBytes();
               // reveiveMsg=new DatagramPacket(newData,newData.length);
                //将转化后的数据发送
                datagramSocket.send(reveiveMsg);
                /**
                 * 重置接收包的长度,因为接收数据的时候已经接收包的长度设置为接收信息的长度,当下次再接收数据的时候,
                 * 新数据的长度大于上一次数据的长度时,多出的数据将被截断,所以要重置接收包缓冲区的长度
                 */
                reveiveMsg.setLength(ECHO_MAX);
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }catch (SocketException se){
            se.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

 上面的代码还有一些未补足的:要在finally 中将所有的流关闭。

 

o
粉丝 1
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
Netty那点事(三)Channel与Pipeline

Channel是理解和使用Netty的核心。Channel的涉及内容较多,这里我使用由浅入深的介绍方法。在这篇文章中,我们主要介绍Channel部分中Pipeline实现机制。为了避免枯燥,借用一下《盗梦空间》的...

黄亿华
2013/11/24
2W
22
Flappy Bird(安卓版)逆向分析(一)

更改每过一关的增长分数 反编译的步骤就不介绍了,我们直接来看反编译得到的文件夹 方法1:在smali目录下,我们看到org/andengine/,可以知晓游戏是由andengine引擎开发的。打开/res/raw/at...

enimey
2014/03/04
6.1K
18
程序猿媛一:Android滑动翻页+区域点击事件

滑动翻页+区域点击事件 ViewPager+GrideView 声明:博文为原创,文章内容为,效果展示,思路阐述,及代码片段。文尾附注源码获取途径。 转载请保留原文出处“http://my.oschina.net/gluoyer...

花佟林雨月
2013/11/09
4.2K
1
5分钟 maven3 快速入门指南

前提条件 你首先需要了解如何在电脑上安装软件。如果你不知道如何做到这一点,请询问你办公室,学校里的人,或花钱找人来解释这个给你。 不建议给Maven的服务邮箱来发邮件寻求支持。 安装Mav...

fanl1982
2014/01/23
1.2W
7
代码生成器--Codgen

Codgen是一个基于数据库元数据模型,使用freemarker模板引擎来构建输出的代码生成器。freemarker的数据模型结构通常来说都是一个Map树状结构模型,codgen也不例外,它的数据模型这棵树的根节...

黄天政
2013/01/29
1.4W
2

没有更多内容

加载失败,请刷新页面

加载更多

SQL 语句大全

点击上方“掌上编程”,选择“置顶或者星标” 优质文章第一时间送达! 一、基础 「1、说明:创建数据库」 CREATE DATABASE database-name    「2、说明:删除数据库」 drop database ...

GeneralMa
昨天
0
0
山东创睦网络科技有限公司:使用Python爬取全球新冠肺炎疫情数据

使用Python爬取全球新冠肺炎疫情数据 导入所需库包 获取实时数据的url 正式编写程序 查看输出结果 导入所需库包 在获取数据之前,我们需要先安装好所需的包requests和pandas: 1.如果是使用p...

osc_qv1fwke0
13分钟前
0
0
如何1年获得别人3年的工作经验(深度好文)

最近有同学问我,为什么你的工作年限不长,技术却这么厉害,我笑了笑,啥也没说。 我不是不想回答,是不知道怎么回答。在他们的定位可能就是,每方面都懂一点,遇到问题能够快速解决,就是比...

zhang_rick
今天
0
0
新基建带动行业

什么是“新基建”? 什么是“新基建”? 根据央视发布的信息来看,其涵盖了5G基站建设、新能源汽车充电桩、大数据中心、人工智能、工业互联网,特高压,城际以及城轨交通,涉及了七大领域和相...

osc_anefoz50
13分钟前
0
0
怕入错行?这群技术人写了本“择业指南”

计算机专业好找工作吗?哪些方向是当前的主流和热门方向呢? 计算机专业的你是不是还在为职业发展纠结犹豫呢? 刚经历完高考选专业的你是不是还在迷茫徘徊呢? 那么福利来啦! 《软件技术职业...

阿里云云栖号
13分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部