Java TCP 编程简介

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

一.TCP 协议简介

http://blog.csdn.net/nvd11/article/details/40954043

之前的博文简单介绍了网络编程中的UDP协议


其实更常用的网络协议是TCP协议.

* UDP协议是不可靠的, 因为UDP协议类似与发邮件, 发送者不会关心接受者的状态. 总之发就是了. 接受者能不能收到是他的事情...  也就是说邮件是有几率会丢失的.

* 而TCP协议是相对可靠的, 类似于打电话, 发送方首先要跟接收方打通1条连接通道(类似首先要打通电话), 然后才能通过这条通道发送信息.  如果接受者不在线, 发送者是无法发送信息的. 

  也就是将大大保证了发送的每条信息, 接受者都能get到.


二.TCP 的若干个名词概念

信息要传输, 必须要有两个party, 分别是发送方和接收方.

而 TCP协议, 发送方和接收方地位是相对的, 也就是说A可以发送信息给B, B也可以发送信息给A.

也就没有发送和接受方的概念了, 可以把A,B可以理解成两个终端.


但是TCP信息双方的两个终端(程序)是可以分成Server端和Client端的.



2.1 Client 程序

好了, 既然信息的两端可以分成Client和Server, 它们之间可以互相发送接受信息, 那么到底是谁是Client, 谁是Server呢.

实际上, 我们定义:

首先发送连接请求的是Client.


就如A电话给B, B接通后它们就可以聊天了,  这时我们认为A是Client, B是Server.


2.2 Server 程序

Server端就是待接通的一方了.

Server端有一个好明显的特性, 也就是将Server端必须长期保持监听(listening)状态.  通俗地讲, Server端的程序必须保持在线.


就如A给B打电话, 作为B, 必须保持电话在线.

而A作为Client, 只需要想打电话时开机就得了. 平时关机也没关系.


2.3 Client - Server - Client

很多时, Client的目的不是想跟Server通信, 而是跟另1个Client通信.

这时, Server就作为1个信息中转的作用.


注意, 这时实际上有两个 TCP通迅的行为了.


分别是Client A 和 ServerB

        和ClientC 和 ServerB


但效果看起来就如A跟C在通信.

地球上大多数聊天工具都是这种模式的.  一旦ServerB挂了, 就不能用了..


2.4 IP地址

TCP协议中, IP地址同样是作为表示网络机器的作用, 就如打电话双方中的电话号码.

究竟要把信息发送到哪里.    作为Server, ip地址一般是固定的, 但是Client则不是.


2.5 端口(Port)

端口表示某条信息到底要发送给制定计算机中的哪1个程序.

例如一个Server 程序B正在监听端口12345,  则所有发送给这个端口的信息, 操作系统都会把这些信息交给这个B程序

但是发送到这个台计算机的另1个端口的信息,  这个B程序是不知道的.


2.6 监听(listening)

监听这个名词相信大家经常见到.

实际上监听代表1个程序里面有1个循环.

这个循环在不断地"尝试" 从某个指定端口接受信息.

简单地讲, 如果程序B正在监听端口12345,  A就发送到这个端口的信息(适当的协议), B都会收到.

但是如果B程序没在监听, 甚至被关闭没在执行, 则收不到这个端口的信息了.



2.7 通道.

我们上面说过, TCP协议两个终端 通信前提是 打通它们之间的通信通道.


实际上,  一条通道的信息传输方向是单向的.


所以TCP协议的两个终端之间实际上会有两条通道, 一条是A通向B的, 另一条是B通向A的.


在编程中, 这两条通道实际上就是两条方向相反的Stream.

对于终端A, 一条是InputStream, 另一条是OutputStream

对于终端B, A的InputStream就是B的OuputStream,  A的OutputStream就是B的InputStream.


2.8 数据字节流Stream

我的博客里有若干关于流(Stream)的博文,  如果不懂什么是流的读者, 没必要往下看了, 强烈建议先去弄懂什么是流.


三.Java TCP协议中的 若干个关键类

3.1 Socket

Socket这个词大家也经常见啦, 它的中文名是"套接字",  很难理解啊, 下面都直接用Socket来称呼它了.


Socket实际就是上面所说的"终端" 程序所使用的发送和接受信息用的工具.


通俗地讲,  假如 A 和 B 打电话,  则A 和 B分别是两个程序,  而Socket就是A和B所使用的电话了.


Socket里面有两个关键方法,

分别是getOutputStream() 和 getInputStream().'


很明显, Socket里面的两条数据流才是通讯的关键嘛.


画一幅图便于理解:


也就是将Socket只不过是程序中使用的一个类, 这个类用于使用TCP协议来发送接受数据.


3.2 ServerSocket

只看这个词, 肯定是与Server有关了,

实际上ServerSocket 是 Server程序中, 用于创建Socket(上面那个类)的一个工厂.


如果在Client端, 我想创建1个Socket对象, 直接用Socket 类的new()方法, 然后制定目标ip和端口,

一旦Socket的对象创建, 则回自动向目标(Server)发送连接请求


但是Server端则必须用ServerSocket的  accept()方法来监听, 一旦收到连接请求.

则会生成Server端的Socket对象,  这个Socket 对象 与 Client端的Socket对象之间就会有两条打通了的方向相反的数据流.



四.一个简单的Java TCP协议小程序


这个程序真的是很简陋的, 它有两个类TCPServer1 和 TCPClient1

一旦TCPServer1被执行,  则它会监听某个指定端口(10019)

一旦TCPClient1被执行, 它会向Server端的10019发送一条信息,  Server收到这个信息后会返回一条确认信息回给Client端..


4.1 TCPServer1.java


import java.net.ServerSocket;
import java.net.Socket;
import java.io.*;

public class TCPServer1{
    private static int port = 10019;

    public static void main(String[] args){
        try{
            tcpServer();
        }
        catch(Exception e){
            e.printStackTrace();    
        }
    }

    public static void tcpServer() throws Exception{
        //ServerSocket is Factory of Socket, 
        ServerSocket ss = new ServerSocket(port);

        //a loop to list the port
        while(true){
            //Function accept is a blocking method, will listing the port, untill get a connect
            //request from a client. it means if no any request form client,
            //the program will keep waiting here...
            //
            //After got a connect request from a client, the ServerSocket will package
            //the connection to a Socket Object 
            //
            //The socket.getInputStream of Server is the same one with the socket.getOutputStream of Client.
            //The socket.getOutputStream of Server is the same one with the socket.getInputStream of Client.
            Socket s = ss.accept();

            System.out.println("A connection is setup!");

            //get a feedback to clent
            DataInputStream dis = new DataInputStream(s.getInputStream());

            //print the message from client, readUTF() is also a blocking method.
            System.out.println(dis.readUTF()); 

            //send a feedback to client.
            DataOutputStream dos = new DataOutputStream(s.getOutputStream());
            dos.writeUTF("Your message is sent to Server successfully!");

            dis.close();
            dos.close();
            s.close();
        }
    }
}

里面的内容大部分是注释啦

流程很简单,

首先建立1个ServerSocket对象,

然后循环监听端口10019.


一旦受到连接请求, 就建立1个Socket对象, 

然后尝试接受1条信息.

然后发送给Client端1条信息.

最后关闭资源



在这个循环中.

每次受到链接请求都有1个Socket对象生成.

所以一般在Server端,   ServerSocket的对象只会有1个

但是Socket对象可能会有多个,  它们分别对应不同Client端.


所以作为网络服务器的Server一定要足够强大, 生产中它必须同时跟多个Client通讯, 而Client实际上只会同1个Server通讯.(或者说利用Server间接地跟其他Client通讯)


值得注意的是s.accept()方法.

这个是1个阻塞方法, 除非受到1个连接请求, 否则程序会卡在这个方法一直等待..



4.2 TCPClient1.java

import java.net.Socket;
import java.io.*;

public class TCPClient1{
    public static String targetIP = "192.168.1.107";
    public static int port = 10019;

    public static void main(String[] args){
        try{
            tcpClient();
        }catch(Exception e){
            e.printStackTrace();
        }    
    }

    public static void tcpClient() throws Exception{
        //Once the Socket Object is created, it will send the connect request to
        //Server, if the connection failed to connect, will prompt excepions..
        //
        //yes, it needs the listing method(socket.accept()) running in Server side.
        Socket s = new Socket(targetIP, port);

        //if no any exception
        //Send a message to Server
        DataOutputStream dos = new DataOutputStream(s.getOutputStream());
        dos.writeUTF("Hi Server!");
        dos.flush();

        //try to get message from Server
        DataInputStream dis = new DataInputStream(s.getInputStream());
        System.out.println(dis.readUTF());

        dos.close();
        dis.close();
        s.close();
    }
}



上面的s.accept()方法在等待什么?

就是等待Client端的 Socket 类的构造方法啊.


看看下面这句代码

Socket s = new Socket(targetIP, port);

Client端的Socket直接使用构造方法创建.

但是

* 必须制定目标(Server)的ip和端口

* Server端必须有程序在监听这个端口.


一旦发现Server端有程序在监听, 则这个对象就会成功创建.

后面就是流的事情了.


否则, 如果Server端那个端口没有程序在监听, 则构造方法会抛出异常...





4.3 执行

分别compile它们成两个类.

放在局域网的两台机器上执行(一台是虚拟机).


就可以看出效果了:










































































猜你喜欢

转载自blog.csdn.net/nvd11/article/details/42847601