Java----Socket编程之模拟客户端Client

Socket的英文原义是“孔”或“插座”,作为BSD UNIX的进程通信机制,取后一种意思。通常也称作”套接字”,网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。
以Java为例,Socket和ServerSocket类库位于java.net包中。ServerSocket用于服务器端,Socket是建立网络连接时使用的。在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话。对于一个网络连接来说,套接字是平等的,并没有差别,不因为在服务器端或在客户端而产生不同级别。不管是Socket还是ServerSocket它们的工作都是通过SocketImpl类及其子类完成的。

1.Socket类的构造

Socket的构造方法有以下几种重载形式:

Socket() 
Socket(InetAddress address, int port)
Socket(InetAddress address, int port, InetAddress localAddr, int localPort) 
Socket(String host, int port)
Socket(String host, int port, InetAddress localAddr, int localPort)

除了第一个不带参数的构造方法以外, 其他构造方法都会试图建立与服务器的连接, 如果连接成功, 就返回 Socket对象; 如果因为某些原因连接失败, 就会抛出IOException .

//使用无参数构造方法, 设定等待建立连接的超时时间   
Socket socket = new Socket();
SocketAddress remoteAddr = new InetSocketAddress(192.168.0.1,9000);
socket.connect(remoteAddr, 60000); //等待建立连接的超时时间为1分钟
//使用服务端IP端口的构造方法
socket = new Socket(192.168.0.1, 9000);
socket.setSoTimeout(60000);//等待建立连接的超时时间为1分钟
//使用对端参数,同时设置客户端的参数信息
InetAddress localAddr = InetAddress.getByName("192.168.0.2");//获取本地IP对应的InetAddress
Socket socket1 = new Socket(192.168.0.1, 9000, localAddr1, 9012);//设置本地端口为9012

Socket 类提供了3 个状态测试方法.

isClosed(): 如果Socket已经连接到远程主机, 并且还没有关闭, 则返回true , 否则返回false .
isConnected(): 如果Socket曾经连接到远程主机, 则返回true , 否则返回false .
isBound(): 如果Socket已经与一个本地端口绑定, 则返回true , 否则返回false .

2.Socket的选项参数设置

Socket 有以下几个选项:
TCP_NODELAY: 表示立即发送数据.
SO_RESUSEADDR: 表示是否允许重用Socket 所绑定的本地地址.
SO_TIMEOUT: 表示接收数据时的等待超时数据.
SO_LINGER: 表示当执行Socket 的 close()方法时, 是否立即关闭底层的Socket.
SO_SNFBUF: 表示发送数据的缓冲区的大小.
SO_RCVBUF: 表示接收数据的缓冲区的大小.
SO_KEEPALIVE: 表示对于长时间处于空闲状态的Socket , 是否要自动把它关闭.
OOBINLINE: 表示是否支持发送一个字节的TCP 紧急数据.
这些具体用法将专门写一篇文章来介绍,在此不多赘述。

3.通过Socket发送/接收数据

如果已成功建立Socket连接,我们如何向其中写入数据呢?需要使用getOutputStream()方法来获得输出流,然后使用write方法写入byte数据。

OutputStream os = socket.getOutputStream();//获取输出流
byte[] packet = "Hello".getBytes("");//将发送数据转换为字节
os.write(packet);//向输出流中写入
os.flush();//刷新缓冲,将缓冲区中的数据全部取出来

同样读取数据使用了InputStream输入流

InputStream is = socket.getInputStream();//获取输入流
byte[] lengthBytes = new byte[8];
is.read(lengthBytes);//读取前八位

4.关闭Socket

Socket通信会占用包括接口在内的很多资源,所以当通信结束时,及时关闭Socket 就显得非常重要, Socket 的 close() 方法负责关闭Socket。为了确保每次通信成功与否都会关闭Socket,所以我们一般将关闭方法写在finally块中。
例如:

Socket socket = null;
try{
    socket = new Socket(192.168.0.1,8000);
    }catch(Exception e){
        e.printStackTrace();
    }finally{
        try{
            if(socket != null){
                socket.close();
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }

4.完整程序示例


import java.io.DataInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketTimeoutException;

public class SocketClient {
    //模拟Socket客户端

    private String host;
    private int port;
    private int soTimeout;

    /** 
     * @Title: send 
     * @Description: 发送报文,用于向指定的服务端发送消息
     * @param msg    发送的消息
     * @param index  
     * @return
     * @throws Exception     
     */     
    public  String send(String msg) throws Exception {
        //发送
        Socket socket = null;
        String data = msg;
        String returnmsg = null;
        try {

            try {
                socket = new Socket(host, port);//建立连接
            }catch(Exception  e){
                System.out.println("连接服务器失败,连接ip:"+host+",端口:"+port);
            }
            socket.setSoTimeout(soTimeout);

            OutputStream os = socket.getOutputStream();
            byte[] packet = data.getBytes("UTF-8");
            os.write(packet);//发送数据
            os.flush();
            InputStream is = socket.getInputStream();
            DataInputStream in=new DataInputStream(is);
            //服务端返回的数据带有8位数据长度,先读取前8位长度,再按照长度读取后面内容
            byte[] lengthBytes = new byte[8];
            is.read(lengthBytes);
            String length = "";
            for(int i=0;i<lengthBytes.length;i++){
                char temp=(char) lengthBytes[i];
                length=length+temp;
            }
            byte returnContent[] = new byte[Integer.parseInt(length)];
            in.read(returnContent);
            returnmsg = new String(returnContent, "UTF-8");
            System.out.println(returnmsg);
            // 读取返回消息
            }catch (Exception e) {
                System.out.println("处理失败,原因:"+e.getMessage());
            } finally {
                try {
                    socket.close();
                } catch (Exception e) {
                    System.out.println();
                }
        }       
        return returnmsg;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public int getSoTimeout() {
        return soTimeout;
    }

    public void setSoTimeout(int soTimeout) {
        this.soTimeout = soTimeout;
    }
}

参考文章:
http://blog.csdn.net/semillon/article/details/7515926

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值