Http Socket TCP区别

本文介绍了TCP/IP协议相关知识。TCP建立需三次握手,断开要四次挥手;HTTP是基于TCP的应用层协议,为短连接。还对比了TCP与UDP特点,分析了UDP优势,介绍了HTTP/HTTPS区别、请求与响应组成。此外,阐述了Socket套接字,包括其特点、通信过程及客户端和服务端操作。

TCP/IP :传输层
建立TCP 需要经过三次握手:
第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。
TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。
断开连接需要经过四次挥手
1:客户端进程发出连接释放报文,并且停止发送数据。此时,客户端进入FIN-WAIT-1(终止等待1)状态
2:服务器收到连接释放报文,发出确认报文,服务端就进入了CLOSE-WAIT(关闭等待)状态。(此时服务器若发送数据,客户端依然要接受).客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文
3:服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
4:客户端收到服务器的连接释放报文后,必须发出确认,服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接(服务器结束TCP连接的时间要比客户端早一些。)

HTTP 超文本协议 ,他是建立TCP协议之上的一种应用.
HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”。(短连接)

Socket 套接字是通讯的基石,是支持TCP/IP协议的网络通信的基本操作单元.
进行网络通信必须的五种信息 :连接协议 ; 本地端口号 ; 本地IP ;远程端口号 ; 远程ip;
在传输中,TCP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个 .为了区分不同应用进程和连接,因此提供了套接字(Socket) .通过Socket来区分不同应用连接通讯.

TPC/IP协议是传输层协议,主要解决数据 如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据。

TCP: 面向连接,可靠的字节流,点对点,传输大量数据,速度慢;
UDP: 不面向连接,易丢失数据不可靠,传输少量数据,速度快;

为什么UDP有时比TCP更有优势?
因为UDP简单传输快的优势,在越来越多场景下取代了TCP(游戏)

HTTP/HTTPS区别
https 需要申请证书,缴费 加密 端口是443 安全的端口协议
http: 不要虚申请证书,超文本协议,不加密 端口是80 不安全

HTTP Request请求: 请求行,请求头部,空行,请求数据四部分组成

请求行: 说明是GRT还是POST请求.
请求头部:
空行:
请求数据: 拼接在URL后面的keyvalue

HTTP 响应也由四部分组成,状态行,消息报头,空行,响应正文

响应正文:
200 ok 请求成功
400 BabeRequest 客户端请求语法错误,不能被服务端所理解
401 Unauthorized 请求未经授权,
403 Forbidden 服务端收到请求,但拒绝提供服务
404 Not Found 资源不存在
500 InternalServiceError 服务器发生了不可预期的错误
503 Service Unabalilable 服务器当前不能处理客户端的请求,一段时间后才能恢复

在这里插入图片描述

TCP/IP是个协议组,可分为四个层次:网络接口层、网络层、传输层和应用层。

在网络层有IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议
在传输层中有TCP协议与UDP协议。
在**应用层有HTTP,**FTP、TELNET、SMTP、DNS等协议。
Http 超文本协议,最显著的特点就是客户端发送完请求需要服务端进行相应,服务端相应后就会释放连接, 从建立连接到关闭连接为一次连接,即短连接

TTPS是HTTP over SSL/TLS,HTTP是应用层协议,TCP是传输层协议,在应用层和传输层之间,增加了一个安全套接层SSL/TLS
SSL (Secure Socket Layer,安全套接字层)

TLS (Transport Layer Security,传输层安全协议)

SSL使用40 位关键字作为RC4流加密算法

socket 为了实现以上的通信过程而建立成来的通信管道,其真实的代表是客户端和服务器端的一个通信进程,双方进程通过socket进行通信,而通信的规则采用指定的协议。

socket只是一种连接模式,不是协议,socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),
通过Socket,我们才能使用TCP/IP协议。tcp、udp,简单的说(虽然不准确)是两个最基本的协议

Socket 传输的特点:
优点

  1. 传输数据为字节级,传输数据可自定义,数据量小(对于手机应用讲:费用低)

2)传输数据时间短,性能高

3)适合于客户端和服务器端之间信息实时交互

4)可以加密,数据安全性强
缺点:

1)需对传输的数据进行解析,转化成应用级的数据

2)对开发人员的开发水平要求高

3)相对于Http协议传输,增加了开发量

客户端
创建socket对象,指定成对的服务端IP地址和端口号
通过socket获取输出流,写入数据发给服务端
通过socket获取输入流,接受服务端的发送的数据
关闭资源close
服务端(与服务端类似)
创建ServerSocket对象,并指定端口号,其端口号必须与客服端一致
通过ServerSocket对象,获取客户端的socket实例(ServerSocket.accept方法)
通过socket获取输入流,接受客户端发来的消息
通过socket获取输出流,写入数据向客户端发送数据作为回应
关闭资源

ps:

new Thread(new Runnable() {
        @Override
        public void run() {
            //IO操作不能放在主线程执行
            connectServer();
        }
    }).start();


private static void connectServer() {
    try {
        //1、创建客户端socket,指定服务端地址和端口
        Socket socket = new Socket("localhost", 8888);
        boolean connected = socket.isConnected(); //检查客户端与服务端是否连接成功
        System.out.println(connected?"连接成功":"连接失败,请重试!");

        //2、获取输出流,向服务器发送消息
        OutputStream outputStream = socket.getOutputStream();
        PrintWriter writer = new PrintWriter(new OutputStreamWriter(outputStream),true);
        writer.write("第一次来到广州\n");
        writer.flush();

        //3、获取输入流,并读取服务端的响应信息
        InputStream inputStream = socket.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        String info=reader.readLine();
        System.out.println("客户端收到服务端回应:"+info);


        //4、关闭资源
        outputStream.close();
        writer.close();
        inputStream.close();
        reader.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

服务端:

 try {
        //1、创建ServerSocket对象,指定与客户端一样的端口号
        ServerSocket serverSocket = new ServerSocket(8888);
        //2、获取Socket实例
        final Socket socket = serverSocket.accept();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //3、获取输入流,接受客户端发来的消息
                    InputStream inputStream = socket.getInputStream();
                    InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
                    BufferedReader reader = new BufferedReader(inputStreamReader);
                    String info=reader.readLine();
                    System.out.println("服务端收到客户端的信息: " +info);

                    //4、获取输出流,向客户端发送消息回应
                    OutputStream outputStream = socket.getOutputStream();
                    PrintWriter writer = new PrintWriter(outputStream);
                    writer.write("羊城欢迎你!"+"\n");
                    writer.flush();

                    //4、关闭IO资源
                    inputStream.close();
                    reader.close();
                    outputStream.close();
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();

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

使用write方法写入数据,字符串必须在中间或者末尾添加转义符\r或者\n,否则在使用readLine方法读取数据时,会一直阻塞从而读取失败。如下:
writer.write(“第一次来到广州\n”);

服务端

public class TCPServerService extends IntentService {

    private static final String[] defaultMessages = {
            "你好啊,嘻嘻",
            "看了你相片,你好帅哦,很喜欢你这样的",
            "我是江西人,你呢?",
            "你在哪里工作?"};

    private int index = 0;

    private boolean isServiceDestroy = false;
     //需注意,必须传入参数
    public TCPServerService() {
        super("TCP");
    }

    @Override
    public void onCreate() {
        super.onCreate();

    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        try {
            //1、监听本地端口号
            ServerSocket serverSocket = new ServerSocket(8954);
            Socket socket = serverSocket.accept();


            //2、获取输入流,接受用户发来的消息(Activity)
            InputStream inputStream = socket.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

            //3、获取输出流,向客户端(Activity)回复消息
            OutputStream outputStream = socket.getOutputStream();
            PrintWriter writer = new PrintWriter(new OutputStreamWriter(outputStream));

            //4、通过循环不断读取客户端发来的消息 ,并发送
            while (!isServiceDestroy) {
                String readLine = reader.readLine();

                if (!TextUtils.isEmpty(readLine)) {
                    String sendMag = index < defaultMessages.length ? defaultMessages[index] : "已离线";
                    SystemClock.sleep(500); //延迟发送
                    writer.println(sendMag+"\r"); // `\r或\n`必须要有,否则会影响客户端接受消息
                    writer.flush();  //刷新流
                    index++;
                }
            }


            //关闭流
            inputStream.close();
            reader.close();
            outputStream.close();
            writer.close();
            socket.close();
            //需关闭,否则再次连接时,会报端口号已被使用
            serverSocket.close();

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

    @Override
    public void onDestroy() {
        super.onDestroy();
        isServiceDestroy = true;
        Log.d(TAG, "onDestroy: ");
    }

    private static final String TAG = "TCPServerService";
}

客户端:

public class SocketActivity extends AppCompatActivity {

    private TextView mTvChatContent;
    private EditText mEtSendContent;
    private Intent mIntent;

    private static final int CONNECT_SERVER_SUCCESS = 0; //与服务端连接成功
    private static final int MESSAGE_RECEIVE_SUCCESS = 1; //接受到服务端的消息
    private static final int MESSAGE_SEND_SUCCESS=2; //消息发送
    @SuppressLint("all")
    private Handler mHandler = new Handler(new Handler.Callback() {

        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what) {
                case CONNECT_SERVER_SUCCESS:
                    //与服务端连接成功
                    mTvChatContent.setText("与聊天室连接成功\n");
                    break;
                case MESSAGE_RECEIVE_SUCCESS:
                    String msgContent = mTvChatContent.getText().toString();
                    mTvChatContent.setText(msgContent+msg.obj.toString()+"\n");
                    break;
                case MESSAGE_SEND_SUCCESS:
                    mEtSendContent.setText("");
                    mTvChatContent.setText(mTvChatContent.getText().toString()+msg.obj.toString()+"\n");
                    break;
            }
            return false;
        }
    });
    private PrintWriter mPrintWriter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_socket);
        mTvChatContent = findViewById(R.id.tv_chat_content);
        mEtSendContent = findViewById(R.id.et_send_content);

        //启动服务
        mIntent = new Intent(this, TCPServerService.class);
        startService(mIntent);

        new Thread(new Runnable() {
            @Override
            public void run() {
                //连接服务端,实现通信交互
                //IO操作必须放在子线程执行
                connectTCPServer();
            }
        }).start();

    }

    private  Socket mSocket=null;
    private void connectTCPServer() {
        //通过循环来判断Socket是否有被创建,若没有则会每隔1s尝试创建,目的是保证客户端与服务端能够连接
        while (mSocket == null) {
            try {
                //创建Socket对象,指定IP地址和端口号
                mSocket = new Socket("localhost", 8954);
                mPrintWriter = new PrintWriter(new OutputStreamWriter(mSocket.getOutputStream()),true);
                if (mSocket.isConnected()) //判断是否连接成功
                    mHandler.sendEmptyMessage(CONNECT_SERVER_SUCCESS);
            } catch (IOException e) {
                e.printStackTrace();
                //设计休眠机制,每次重试的间隔时间为1s
                SystemClock.sleep(1000);
            }

        }

        //通过循环来,不断的接受服务端发来的消息
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
            while (!SocketActivity.this.isFinishing()){ //当Activity销毁后将不接受
                String msg = reader.readLine();
                if (!TextUtils.isEmpty(msg)){
                    //发消息通知更新UI
                    mHandler.obtainMessage(MESSAGE_RECEIVE_SUCCESS,msg).sendToTarget();
                }

            }
            //关闭流
            mPrintWriter.close();
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }



    }


    @SuppressLint("SetTextI18n")
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.but_send:
                //必须开启子线程,不能在UI线程操作网络
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        String msg = mEtSendContent.getText().toString();
                        if (mPrintWriter!=null && !TextUtils.isEmpty(msg)){
                            mPrintWriter.println(msg+"\n");
                            //此处可以不用刷新流的方法,因为在创建mPrintWriter对象时,在其构造方法中设置了自动刷新缓存
//                            mPrintWriter.flush(); 
                            //通知更新UI
                            mHandler.obtainMessage(MESSAGE_SEND_SUCCESS,msg).sendToTarget();
                        }
                    }
                }).start();


                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //关闭输入流和连接
        if (mSocket!=null){
            try {
                mSocket.shutdownInput();
                mSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //停止后台服务
        stopService(mIntent);
    }

    private static final String TAG = "TCPServerService";
}

Mainfest:

 <uses-permission android:name="android.permission.INTERNET"/>
 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<service android:name=".socket.TCPServerService"
            android:exported="true"
            android:process=":socket"/>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值