zoukankan      html  css  js  c++  java
  • 基于TCP和UDP的Socket实现(JAVA)

     本文介绍如何用Java实现Socket编程。首先介绍Java针对Socket编程提供的类,以及它们之间的关系。然后分别针对TCP和UDP两种传输层协议实现Socket编程。

    1 Java中的Socket编程接口介绍

    Java为Socket编程封装了几个重要的类。

    1.1 Socket类

    Socket类实现了一个客户端socket,作为两台机器通信的终端,默认采用的传输层协议为TCP,是一个可靠传输的协议。Socket类除了构造函数返回一个socket外,还提供了connect, getOutputStream, getInputStream和close方法。connect方法用于请求一个socket连接,getOutputStream用于获得写socket的输出流,getInputStream用于获得读socket的输入流,close方法用于关闭一个流。

    1.2 DatagramSocket类

    DatagramSocket类实现了一个发送和接收数据报的socket,传输层协议使用UDP,不能保证数据报的可靠传输。DataGramSocket主要有send, receive和close三个方法。send用于发送一个数据报,Java提供了DatagramPacket对象用来表达一个数据报。receive用于接收一个数据报,调用该方法后,一直阻塞接收到直到数据报或者超时。close是关闭一个socket。

    1.3 ServerSocket类

    ServerSocket类实现了一个服务器socket,一个服务器socket等待客户端网络请求,然后基于这些请求执行操作,并返回给请求者一个结果。ServerSocket提供了bind、accept和close三个方法。bind方法为ServerSocket绑定一个IP地址和端口,并开始监听该端口。accept方法为ServerSocket接受请求并返回一个Socket对象,accept方法调用后,将一直阻塞直到有请求到达。close方法关闭一个ServerSocket对象。

    1.4 SocketAddress

    SocketAddress提供了一个socket地址,不关心传输层协议。这是一个虚类,由子类来具体实现功能、绑定传输协议。它提供了一个不可变的对象,被socket用来绑定、连接或者返回数值。

    1.5 InetSocketAddress

    InetSocketAddress实现了IP地址的SocketAddress,也就是有IP地址和端口号表达Socket地址。如果不制定具体的IP地址和端口号,那么IP地址默认为本机地址,端口号随机选择一个。

    1.6. DatagramPacket

    DatagramSocket是面向数据报socket通信的一个可选通道。数据报通道不是对网络数据报socket通信的完全抽象。socket通信的控制由DatagramSocket对象实现。DatagramPacket需要与DatagramSocket配合使用才能完成基于数据报的socket通信。

     2. 基于TCP的Socket编程

    上面描述了Java对Socket编程提供的接口,本节介绍如何实现一个基于TCP连接的Socket通信。

    下面例子是Server端等待从Client端接收一条消息,然后再给客户端发送一个消息。

    服务器端首先实例化ServerSocket对象,然后为其绑定一个本机地址,并开始监听。一直阻塞状态下等待客户端请求,当获得客户端连接请求后,返回一个socket对象。然后用这个socket接收一条消息,并发送一条消息。代码如下:

    package server.socket.java;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.net.InetAddress;
    import java.net.InetSocketAddress;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.net.SocketAddress;
    
    public class SocketTcp {
        static private String TAG = "SocketTcp: ";
        
        public static void main(String[] args){
            try {
                ServerSocket server = new ServerSocket();
                SocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(), 10001);
                server.bind(address);
                System.out.println("==waiting for being connected...");
                Socket client = server.accept();
                System.out.println("==connected with " + 
                        client.getRemoteSocketAddress() );
                
                PrintWriter socketOut = new PrintWriter(client.getOutputStream());
                
                System.out.println("==waiting message from client...");
                byte buf[] = new byte[1024];
                if ( client.getInputStream().read(buf) > 0 ) {
                    System.out.println("Receive Message: " + new String(buf));
                }
                
                System.out.println("==sending message to client...");
                String sendStr = "This is the message for client.";
                socketOut.write(sendStr);
                socketOut.flush();
                
                socketOut.close();
                client.close();
                server.close();
            } catch (IOException e) {
                System.out.println(TAG + e.getMessage());
                e.printStackTrace();
            }
        }
    }
    
    

     客户端首先实例化一个socket对象,用这个对象连接服务器端。连接成功后,发送一条消息,然后等待接收一条消息。代码如下:

    package client.socket.java;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.InetAddress;
    import java.net.InetSocketAddress;
    import java.net.Socket;
    import java.net.SocketAddress;
    
    public class SocketTcp {
        static private String TAG = "SocketTcp: ";
        
        public static void main(String[] args){
            try {
                final Socket socket = new Socket();
                SocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(), 10001);
                System.out.println("==connecting to server ...");
                socket.connect(address);
                
                PrintWriter socketOut = new PrintWriter(socket.getOutputStream());
                BufferedReader socketIn = new BufferedReader(
                        new InputStreamReader(socket.getInputStream()) );
                
                String sendStr = "This is the message for server.";
                System.out.println("==sending message to server ...");
                socketOut.write(sendStr);
                socketOut.flush();
                System.out.println("==waiting message from server ...");
                String receiveStr = socketIn.readLine();
                System.out.println("Receive Message: " + receiveStr);
                
                socketOut.close();
                socketIn.close();
                socket.close();
            } catch (IOException e) {
                System.out.println(TAG + e.getMessage());
                e.printStackTrace();
            } finally {
                
            }
        }
    }

     服务器端运行结果: 

    ==waiting for being connected...
    ==connected with /172.26.176.69:53912
    ==waiting message from client...
    Receive Message: This is the message for server.

     客户端运行结果: 

    ==connecting to server ...
    ==sending message to server ...
    ==waiting message from server ...
    Receive Message: This is the message for client.

     3 基于UDP的Socket编程示例

     基于UDP的Socket编程与基于TCP的socket编程稍有不同,socket server和client都用DatagramSocket实现。

     下面例子是Server端等待从Client端接收一条消息,然后再给客户端发送一个消息。

     服务器端首先实例化DatagramSocket对象,然后为其绑定一个本机地址,并开始监听。一直阻塞状态下等待从客户端接收数据报。然后从数据报中获取数据报的源地址,然后用这个源地址作为目的地址打包一个数据报,然后发送出去。代码如下:

    package server.socket.java;
    
    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    import java.net.InetSocketAddress;
    import java.net.SocketAddress;
    import java.net.SocketException;
    import java.net.UnknownHostException;
    
    public class SocketUdp {
        final private static String TAG = "SocketUdp: ";
        
        public static void main(String args[]) {
            DatagramSocket socket = null;
            DatagramPacket datapacket = null;
            InetSocketAddress address = null;
            
            try {
                address = new InetSocketAddress(InetAddress.getLocalHost(), 7778);
                socket = new DatagramSocket(address);
                // socket.bind(address);
                
                byte buf[] = new byte[1024];
                datapacket = new DatagramPacket(buf, buf.length);
                System.out.println("==block for receive messages...");
                socket.receive(datapacket);
                buf = datapacket.getData();
                InetAddress addr = datapacket.getAddress();
                int port = datapacket.getPort();
                System.out.println("Message Content: " + new String(buf) );
                System.out.println("Receive From " + addr + ":" + port);
                
                SocketAddress toAddress = datapacket.getSocketAddress();
                String sendStr = "I'm Server, this is the message for client.";
                buf = sendStr.getBytes();
                datapacket = new DatagramPacket(buf, buf.length);
                datapacket.setSocketAddress(toAddress);
                socket.send(datapacket);
                System.out.println("==message sended");
                
            } catch (UnknownHostException e) {
                System.out.println(TAG + e.getMessage());
                e.printStackTrace();
            } catch (SocketException e) {
                System.out.println(TAG + e.getMessage());
                e.printStackTrace();
            } catch (IOException e) {
                System.out.println(TAG + e.getMessage());
                e.printStackTrace();
            }
        }
    
    }

      客户端首先实例化一个DatagramSocket对象。利用服务器地址和端口号作为目的地址打包一个数据报,并发送。然后等待从服务器回复的数据报。代码如下: 

    package client.socket.java;
    
    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    import java.net.InetSocketAddress;
    import java.net.SocketException;
    import java.net.UnknownHostException;
    
    public class SocketUdp {
        final private static String TAG = "SocketUdp: ";
        
        public static void main(String args[]) {
            try {
                DatagramSocket getSocket = new DatagramSocket();
                DatagramPacket datapacket = null;
                InetSocketAddress toAddress = new InetSocketAddress(InetAddress.getLocalHost(), 7778);
                
                String sendStr = "I'm client, this is the message for server.";
                byte buf[] = sendStr.getBytes();
                datapacket = new DatagramPacket(buf, buf.length);
                datapacket.setSocketAddress(toAddress);
                getSocket.send(datapacket);
                System.out.println("==message sended");
                
                System.out.println("==block for receive messages...");
                getSocket.receive(datapacket);
                buf = datapacket.getData();
                System.out.println("Message Content: " + new String(buf));
            } catch (SocketException e) {
                System.out.println(TAG + e.getMessage());
                e.printStackTrace();
            } catch (UnknownHostException e) {
                System.out.println(TAG + e.getMessage());
                e.printStackTrace();
            } catch (IOException e) {
                System.out.println(TAG + e.getMessage());
                e.printStackTrace();
            }
            
        }
    }

     服务器端运行结果:

    ==block for receive messages...
    Message Content: I'm client, this is the message for server.

     客户端运行结果:

    ==message sended
    ==block for receive messages...
    Message Content: I'm Server, this is the message for client.
  • 相关阅读:
    java笔记使用线程池优化多线程编程
    java笔记查看和修改线程名称
    java笔记查看和修改线程的优先级
    java笔记策略模式和简单工厂模式
    java笔记用ThreadLocal管理线程,Callable<V>接口实现有返回值的线程
    java笔记枚举总结与详解
    java笔记关于克隆技术
    java笔记反射机制之基础总结与详解
    java笔记使用事件分配线程更新Swing控件
    java笔记关于int和byte[]的转换
  • 原文地址:https://www.cnblogs.com/hongyanee/p/3288184.html
Copyright © 2011-2022 走看看