Java socket

知识储备

模型

  • 通信模型主要是基于CS结构。通信一方作为服务器(Server)先运行(一般作为守护进程始终运行)、监听端口、并等待客户端提出请求。
  • 难点:通信双方建立连接;通信双方进行可靠高效数据传输(TCP/UDP)。在TCP/IP 协议中,IP层负责网络主机定位,TCP提供面向应用的可靠(tcp)的或非可靠(udp)的数据传输机制。

引在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。
TCP是Transmission Control Protocol的 简称,是一种面向连接的可靠传输的协议。通过TCP协议传输。发送方和接收方的成对的两个socket之间必须建立连接,以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输。
UDP是User Datagram Protocol的简称,是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。

TCP原理

基本概念
  • 位码:TCP标志位。6种SYN(synchronous建立联机) 、ACK(acknowledgement 确认) 、PSH(push传送) FIN(finish结束)、 RST(reset重置) 、URG(urgent紧急)
  • seq:sequence number。数据包本身的序列号
  • ack:Acknowledge number。确认序号:期望对方继续发送的那个数据包的序列号
三次握手

大致图解,每次握手涉及的标志位

详细图解

  1. 第一次握手:Client将标志位SYN置为1,随机产生一个值seq=x,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
  2. 第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYNACK都置为1,ack=x+1,随机产生一个值seq=y,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
  3. 第三次握手:Client收到确认后,检查ack是否为x+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=y+1,并将该数据包发送给Server,Server检查ack是否为y+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。
四次挥手

http://blog.chinaunix.net/uid-7411781-id-3812206.html
四次挥手

客户端和服务端总共发送4个包以确认连接的断开。
于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了
但是在这个TCP连接上仍然能够发送数据,直到另一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭。

四挥过程
  1. 第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
  2. 第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
  3. 第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
  4. 第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。
注意

为什么连接的时候是三次握手,关闭的时候却是四次握手?
A:因为建立连接时:当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但关闭连接时:当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,”你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

socket编程

概念

网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket。
Socket通常用来实现客户方和服务方的连接。
Socket是TCP/IP协议的一个十分流行的编程界面,一个Socket由一个IP地址和一个端口号唯一确定。

涉及2个类,均在java.net包下。
1. Socket:
2. ServerSocket:

交互过程

图解如下:
这里写图片描述

代码

服务器端程序

Server.java

package xianggen.socket;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import java.net.ServerSocket;
import java.net.Socket;
/**
 * 
 * @author xianggen
 *
 */
public class Server {
    public static void main(String[] args) {
        Server manager = new Server();
        manager.doListen();
    }

    /**
     * 服务器监听
     * 多线程支持多客户端
     */
    public void doListen() {
        ServerSocket server;
        try {
//          创建一个ServerSocket在端口9991监听客户请求
            server = new ServerSocket(9991);
            while (true) {
//              使用accept()阻塞等待客户请求,有客户请求到来就产生一个socket对象,并继续执行
                Socket client = server.accept();
                Thread thread=new Thread(new SSocket(client));
                thread.start();
                System.out.println("thread name:"+thread.getName());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    //服务器进程
    class SSocket implements Runnable {

        Socket client;

        public SSocket(Socket client) {
            this.client = client;
//            System.out.println("client port:"+client.getPort());
        }



        public void run() {
            DataInputStream input;
            DataOutputStream output;
            try {
                input = new DataInputStream(client.getInputStream());
                output = new DataOutputStream(client.getOutputStream());
                while(true){
                    String listMsg = input.readUTF();
                    System.out.println(listMsg);

                    output.writeUTF(new DataInputStream(System.in).readLine());
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
客户端程序

Client2.java


/**
 * @author xianggen
 *
 */
package xianggen.socket;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client2 {
    public static void main(String[] args) {
        Socket socket = null;
        try {
//          向本机(我的本机ip为:10.18.34.133)的9991端口发出客户请求
            socket = new Socket("10.18.34.113", 9991);
            OutputStream netOut = socket.getOutputStream();
            DataOutputStream doc = new DataOutputStream(netOut);
            DataInputStream in = new DataInputStream(System.in);
//          循环发送信息
            while(true)
                doc.writeUTF(in.readLine());

        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } 
        {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                }
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值