【J2SE快速进阶】——Socket编程入门(TCP/UDP)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huyuyang6688/article/details/44645323

        作品展时,我们的作品 “超级飞聊” 的主打功能就是聊天,包括局域网聊天、外网聊天等,虽然那时是用VB实现的(winsock控件),不过每种编程中的思想还是大同小异的,所以学习Java中的Socket编程时,倍感亲切啊。

概念了解

       Socket又称“套接字”,用来向网络中的主机发出请求或者应答网络中发出的请求。

       文章开头先来简单了解一下TCP与UDP这两个协议:

TCP

       TCP(Transmission Control Protocol传输控制协议)是一种面向连接的、可靠的、基于字节流的通信协议,位于传输层。这三个特点中,面向连接就如同打电话,双方的电话必须保持连接状态才能通话;可靠就如同QQ上的视频,一方发送视频请求,另一方必须同意后才能建立视频连接,也可以说安全性好;基于字节流,继续看下文就行。

       TCP最重要的思想就是大名鼎鼎的“三次握手”:

       客户端向服务端发送请求报文,服务端收到后向客户端回复,客户端确认收到服务端的回复。三次握手完成后,客户端就与服务端建立了可靠的链接。

UDP

        UDP(User Datagram Protocol用户数据报协议),提供简单但不可靠的信息传送服务。很像生活中的写信或发邮件,不需要征得对方的同意,不需要与对方建立连接,就可以将数据发送出去,但是不能保证发送出去的数据能够确保无误地到达目的地。

       我们常用的ping命令就是基于UDP协议,telnet命令就是基于TCP协议。

       记得在VB中使用winsock,先往窗体上拖两个winsock控件(相当于实例化),然后给它们设置IP、端口、传输协议,就可以通信了。只不过在Java中,基于TCP协议的通信需要用ServerSocket和Socket来完成,基于UDP协议的通信需要用 DatagramSocket和DatagramPacket来完成。

       下面从TCP和UDP两个方面来举例说明Java中如何进行网络通信。

基于TCP协议的通信

        服务端代码:

import java.io.*;
import java.net.*;
public class Server {	
	public static void main(String[] args) {
		InputStream is=null; 
		OutputStream os=null;
		try{
			ServerSocket ss=new ServerSocket(5566);         //创建服务器套接字并绑定到5566端口
			Socket s=ss.accept();
			is=s.getInputStream();
			os=s.getOutputStream();
			DataInputStream dis=new DataInputStream(is);
			DataOutputStream dos=new DataOutputStream(os);
			String message=null;
			if((message=dis.readUTF())!=null){              //接收并输出此连接的客户端发来的信息
				System.out.println("Client:"+message);
			}
			dos.writeUTF("Hello, Client!");                //向此连接的客户端发送信息
			dis.close();
			dos.close();
			s.close();
		}catch(ConnectException ex){
			ex.printStackTrace();
		}catch(IOException ex){
			ex.printStackTrace();
		}
	}
}

        客户端代码:

import java.io.*;
import java.net.*;
public class Client {
	public static void main(String[] args) {
		InputStream is=null;
		OutputStream os=null;
		try{
			Socket s=new Socket("127.0.0.1",5566);         //创建一个套接字并将其连接到127.0.0.1地址(本机)的5566端口
			is=s.getInputStream();
			os=s.getOutputStream();
			DataInputStream dis=new DataInputStream(is);
			DataOutputStream dos=new DataOutputStream(os);
			dos.writeUTF("Hello, Server!");               //向服务端发送信息
			String message=null;
			if((message=dis.readUTF())!=null){
				System.out.println("Server:"+message);    //接收并输出服务端发来的信息
			}
			dis.close();
			dos.close();
			s.close();			
		}catch(ConnectException ex){
			ex.printStackTrace();
		}catch(IOException ex){
			ex.printStackTrace();
		}
	}
}

         执行结果:

客户端: 

                服务端:

         整个连接和交互的过程如下图:

执行时,先启动服务端,服务端创建服务器套接字ServerSocket并绑定到指定的端口,当执行到Socket s=ss.accept()时,会产生“阻塞”(即让程序暂时停留在此处),但客户端启动,创建套接字Socket并向指定地址的指定端口发送请求时,ServerSocket接受服务端的请求并返回客户端的socket实例,与之建立连接。socket原意为插座,还真的挺形象的,整个过程就如同把客户端的插头插到服务端的插座上,就建立起了通道。通信完毕后,双方都关闭连接。

        例子中,Socket的getInputStream()方法可以获得网络连接输入,返回此套接字的字节输入流对象;getOutputStream()方法返回此套接字的字节输出流对象,用于向连接对象写入数据。这里体现了上文中TCP的第三个特点“基于字节流”。

基于UDP协议的通信

        服务端代码:

import java.net.*;
class UDPServer{
    public static void main(String[] args)throws Exception{
    	//接收信息
        DatagramSocket  server = new DatagramSocket(5050);
        byte[] recvBuf = new byte[1000];
        DatagramPacket recvPacket = new DatagramPacket(recvBuf , recvBuf.length);
        server.receive(recvPacket);
        String recvStr = new String(recvPacket.getData() , 0 , recvPacket.getLength());
        System.out.println("What server has received is:" + recvStr);
        
        //发送信息
        int port = recvPacket.getPort();
        InetAddress addr = recvPacket.getAddress();
        String sendStr = "Hello ! I'm Server";
        byte[] sendBuf = new String("Hello Client! I'm Server!").getBytes();    
        DatagramPacket sendPacket 
            = new DatagramPacket(sendBuf , sendBuf.length , addr , port );
        server.send(sendPacket);
        server.close();
    }
}

        客户端代码:

import java.net.*;
class UDPClient{
    public static void main(String[] args)throws Exception{
    	//发送信息
        DatagramSocket client = new DatagramSocket();       
        byte[] sendBuf=new String("Hello Server! I'm Client").getBytes();       
        InetAddress addr = InetAddress.getByName("127.0.0.1");
        int port = 5050;
        DatagramPacket sendPacket 
            = new DatagramPacket(sendBuf ,sendBuf.length , InetAddress.getByName("127.0.0.1") , port);
        client.send(sendPacket);
        
        //接收信息
        byte[] recvBuf = new byte[100];
        DatagramPacket recvPacket = new DatagramPacket(recvBuf , recvBuf.length);
        client.receive(recvPacket);
        String recvStr = new String(recvPacket.getData() , 0 ,recvPacket.getLength());
        System.out.println("What client has received is:" + recvStr);
        client.close();
    }
}

        整个流程如下图:

        服务端启动后,准备一个包含字节数组buf的数据报包DatagramPacket用于接收客户端发来的数据报,客户端启动后,将目的地址、端口、发送内容等信息封装在DatagramPacket中,通过DatagramSocket的send()方法发往目的地(服务端),服务端将接收到的数据报放在DatagramPackage中。服务端向客户端发送数据报的过程亦然。

       文章前面说了TCP三次握手,客户端发送请求、服务端接受请求并返回确认信息,客户端收到确认信息后再发送确认收到确认信息,简单的三个步骤,过程却非常复杂(而且TCP断开连接时还需要四次挥手)。因为UDP协议不需要连接的过程,所以它的效率高,速度快,同时也因如此,UDP的可靠性不如TCP高。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏禁心尽力

关于网络编程

说起网络编程,通俗的说就是Socket编程。 使用对象InetAddress,因为该对象无构造函数,故不用new对象即可使用。 获取一个已知主机名的IP地址和主...

21610
来自专栏前端大白专栏

关于ant-design表单问题

3124
来自专栏Golang语言社区

【转】Go语言Http Server源码阅读

目录(?)[-] 前言 几个重要概念 具体分析 几个接口 Handler ResponseWriter Flusher Hijacker response H...

2924
来自专栏Java帮帮-微信公众号-技术文章全总结

第二十六天 网络编程【悟空教程】

在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。

1576
来自专栏架构之路

【网络编程系列】二:socket通信原理及实践

我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览器浏览网页时,浏览器的进程怎么与web服务器通信的?当你用QQ聊天时,QQ进程怎么与服务器或...

5816
来自专栏刘望舒

Android系统启动流程(四)Launcher启动过程与系统启动流程

前言 此前的文章我们学习了init进程、Zygote进程和SyetemServer进程的启动过程,这一篇文章我们就来学习Android系统启动流程的最后一步:L...

2518
来自专栏刘望舒

Android Apk安装过程解析

静默安装 apk安装流程简析 installd进程意义 最近工作上遇到静默安装相关的内容,顺便学习一下apk安装的知识

3006
来自专栏Golang语言社区

"LollipopGo/library/lollipop/common" 测试3

Golang语言社区 开源轻量级web应用框架,可以快速创建博客及商城等

5039
来自专栏SDNLAB

OpenDaylight与Mininet应用实战之三层转发机制四

本文属于该专题中的进阶篇,主要讲解ODL应用不同网段的三层数据转发机制,在OpenDaylight与Mininet应用实战之流表操作(三)中会涉及到相同网段的二...

5026
来自专栏CRPER折腾记

React 折腾记 - (5) 记录用React开发项目过程遇到的问题(Webpack4/React16/antd等)

技术栈: react@16.6.0/ react-router-dom@v4 / webpack^4.23.1(babel7+)

2372

扫码关注云+社区

领取腾讯云代金券