TCP及Socket

TCP及Socket,第1张

计算机网络相关的问题,如果想去了解,前提就是深刻理解网络4/7层模型。

记住并理解,上面每一层。切记,切记,切记。知道一些就可以开始主题,分两个部分TCP和Socket。

TCP是(Tranfer Control Protocol)的简称,在OSI参考模型第四层,也就是端口,到端口的的通信,它是一个可靠的双向连接,一旦建立连接就可以双向数据传输,双方都可以进行发送或接收 *** 作。

最常听说的就是三次握手。是的它说的就是TCP建立连接的过程。具体的步骤如下:

第一步:Server监听端口,状态为:Listen 

第二部:Client发送SNY包,请求连接,并将状态改为:SYN_SEND

第三部:Server发送ACK包,和SNY包,同意,并请求连接,状态改为:SYN_RCVD

第四部:Client发送ACK包,Server收到包后,连接建立。双方状态改为:ESTABLISHED

第一步:Client发起FIN包。状态变为:FNI_WAIT_1

第二步:Server发送ACK包。状态变为:CLOSE_WAIT,Client收包后状态变为:FNI_WAIT_2

第三步:Server发送FIN包,状态变为:LAST_ACK。Client收包后状态变为:TIME_WAIT

第四步:Client发送ACK包。双方状态变为:CLOSED 

需要注意的是,Client是在收到Server FIN包后两个最大报文时间(2MSL)后变为CLOSED状态的。双方都可以发起断开请求,上面是已先发起请求的是Client。

如何验证上面讲的这些呢?那就是抓包分析,其实日常的开发中也可以通过抓包来发现问题。在这里我简单贴个图看一下TCP的包,这个工具非常强大感兴趣的朋友可以去深入了解一下。

1可以在这个过滤,通过协议,通过IP,通过端口都可以。

2这个就是每个包,例子中的这个是个[SYN,ACK]包,就是建立TCP连接的第二次握手

3被抓取的包对应的网络层,从上到下分别是:物理层、数据链路层、网络层、传输层。

Socket其实就是TCP协议的实现。也就是说它就是TCP的API,当然其实Socket也支持别的协议如:UDP。既然是API那,上面说的其实就是它的原理。下面说一下它的使用。大概说一下。

1ServerSocket:是服务端来监听的类。监听方法accept()。

2客户端:创建Socket对象,设定IP和Port

3当有新的客户端连接时可以通过ServerSocket类获取Socket。而Socket就是我们的通讯渠道。

4发送和读取数据分别使用OutputStream和InputStream而这两个类是从Socket获取的。

其实Socket的基本使用就是这么简单,但是在其实项目中这样是无法满足需求的。实际上大多数场景都是需要一对多的提供服务。

使用多线程实现多客户端的通信

实现服务器与多个客户端进行通信, 可以接受多个客户端的请求并进行回复

应用多线程来实现服务器与多客户端之间的通信

1、服务器端创建ServerSocket,循环调用accept()等待客户端连接

2、客户端创建一个Socket并请求和服务器端连接

3、服务器端接受客户端请求,创建socket与该客户建立专线连接

4、建立连接的两个socket在一个单独的线程上对话

5、服务器端继续等待新的连接

这种东西,Google下大把吧,正好前阵子有一个TCP通讯的,借你参考下好了:

Server Side

package nio;

import javaioByteArrayOutputStream;

import javaioIOException;

import javanetInetSocketAddress;

import javanetServerSocket;

import javanioByteBuffer;

import javaniochannelsSelectionKey;

import javaniochannelsSelector;

import javaniochannelsServerSocketChannel;

import javaniochannelsSocketChannel;

import javatextDateFormat;

import javatextSimpleDateFormat;

import javautilDate;

public class EchoServer {

    private static int SOCKET_NUM = 55555;

    private static DateFormat dateFormatter = new SimpleDateFormat("yyyyMMdd HH:mm:ss");

    

    /

      @param args

     /

    public static void main(String[] args) {

        new EchoServer()start();

    }

    public void start() {

        try {

            Selector selector = bindServer();  // 绑定服务端口,并定义一个事件选择器对象记录套接字通道的事件

            

            / 通过此循环来遍例事件 /

            while (true) {

                log("Waiting events");

                int n = selectorselect(); // 查询事件如果一个事件都没有,这里就会阻塞

                log("Got events: " + n);

                

                ByteBuffer echoBuffer = ByteBufferallocate(50); // 定义一个byte缓冲区来存储收发的数据

                / 循环遍例所有产生的事件 /

                for (SelectionKey key : selectorselectedKeys()) {

                    SocketChannel sc;

                    selectorselectedKeys()remove(key);  // 将本此事件从迭带器中删除

                    

                    / 如果产生的事件为接受客户端连接(当有客户端连接服务器的时候产生) /

                    if ((keyreadyOps() & SelectionKeyOP_ACCEPT) == SelectionKeyOP_ACCEPT) {

                        

                        ServerSocketChannel subssc = (ServerSocketChannel) keychannel(); // 定义一个服务器socket通道

                        

                        sc = subsscaccept(); // 将临时socket对象实例化为接收到的客户端的socket

                        

                        scconfigureBlocking(false); // 将客户端的socket设置为异步

                        

                        scregister(selector, SelectionKeyOP_READ); // 将客户端的socket的读取事件注册到事件选择器中

                       

                        Systemoutprintln("Got new client:" + sc);

                    }

                    / 如果产生的事件为读取数据(当已连接的客户端向服务器发送数据的时候产生) /

                    else if ((keyreadyOps() & SelectionKeyOP_READ) == SelectionKeyOP_READ) {

                        

                        sc = (SocketChannel) keychannel(); // 临时socket对象实例化为产生本事件的socket

                        

                        ByteArrayOutputStream bos = new ByteArrayOutputStream(); // 定义一个用于存储byte数据的流对象,存储全部信息

                        

                        echoBufferclear(); // 先将客户端的数据清空

                        

                        try {

                            // 循环读取所有客户端数据到byte缓冲区中,当有数据的时候read函数返回数据长度

                            // NIO会自动的将缓冲区一次容纳不下的自动分段

                            int readInt = 0; // 为读取到数据的长度

                            while ((readInt = scread(echoBuffer)) > 0) {

                                // 如果获得数据长度比缓冲区大小小的话

                                if (readInt < echoBuffercapacity()) {

                                    

                                    byte[] readByte = new byte[readInt]; // 建立一个临时byte数组,将齐长度设为获取的数据的长度

                                    // 循环向此临时数组中添加数据

                                    for (int i = 0; i < readInt; i++) {

                                        readByte[i] = echoBufferget(i);

                                    }

                                    

                                    boswrite(readByte); // 将此数据存入byte流中

                                }

                                // 否则就是获得数据长度等于缓冲区大小

                                else {                                    

                                    boswrite(echoBufferarray()); // 将读取到的数据写入到byte流对象中

                                }

                            }

                            // 当循环结束时byte流中已经存储了客户端发送的所有byte数据

                            log("Recive msg: " + new String(bostoByteArray()));

                        } catch (Exception e) {

                            

                            eprintStackTrace(); // 当客户端在读取数据 *** 作执行之前断开连接会产生异常信息

                            

                            keycancel(); // 将本socket的事件在选择器中删除

                            break;

                        }

                        

                        writeBack(sc, bostoByteArray()); // 向客户端写入收到的数据

                    }

                }

            }

        } catch (Exception e) {

            eprintStackTrace();

        }

    }

    /

      绑定服务端口,初始化整个服务

      @throws IOException

     /

    private Selector bindServer() throws IOException {

        log("Start binding server socket:" + SOCKET_NUM);

        

        Selector selector = Selectoropen(); // 定义一个事件选择器对象记录套接字通道的事件

        ServerSocketChannel ssc = ServerSocketChannelopen(); // 定义一个异步服务器socket对象

        sscconfigureBlocking(false);// 将此socket对象设置为异步

        ServerSocket ss = sscsocket(); // 定义服务器socket对象-用来指定异步socket的监听端口等信息

        InetSocketAddress address = new InetSocketAddress(SOCKET_NUM); // 定义存放监听端口的对象

        ssbind(address); // 将服务器与这个端口绑定

        sscregister(selector, SelectionKeyOP_ACCEPT); // 将异步的服务器socket对象的接受客户端连接事件注册到selector对象内

        log("Binded socket at:" + SOCKET_NUM);

        

        return selector;

    }

    

    private boolean writeBack(SocketChannel sc, byte[] b) {

        ByteBuffer echoBuffer = ByteBufferallocate(blength); // 建立这个byte对象的ByteBuffer

        echoBufferput(b); // 将数据存入 

        

        echoBufferflip(); // 将缓冲区复位以便于进行其他读写 *** 作

        try {

            // 向客户端写入数据,数据为接受到数据

            scwrite(echoBuffer);

        } catch (IOException e) {

            eprintStackTrace();

            return false;

        }

        Systemoutprintln("Msg echo back: " + new String(echoBufferarray()));

        return true;

    }

    private static void log(Object msg) {

        Systemoutprintln("SERVER [" + dateFormatterformat(new Date()) + "]: " + msg);

    }

}

你好,listen只是设定了等待连接的最大数,因为你有线程接收连接,所以一般不会出现连接不上的情况。

你可以设定一个的int 类型的数据表示当前连接数,当超过这个数就不处理连接了,然后返回给客户端一个数据,让客户端接收到这个数据后知道已经超过最大数了,然后释放连接。

主要是你通过socket api封装要发送的数据,内部会自动封装成数据流进行传输。

1,什么是Socket

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

但是,Socket所支持的协议种类也不光TCP/IP一种,因此两者之间是没有必然联系的。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。

2,Socket通讯的过程

Server端Listen(监听)某个端口是否有连接请求,Client端向Server 端发出Connect(连接)请求,Server端向Client端发回Accept(接受)消息。一个连接就建立起来了。Server端和Client 端都可以通过Send,Write等方法与对方通信。

对于一个功能齐全的Socket,都要包含以下基本结构,其工作过程包含以下四个基本的步骤:

(1) 创建Socket;

(2) 打开连接到Socket的输入/出流;

(3) 按照一定的协议对Socket进行读/写 *** 作;

(4) 关闭Socket(在实际应用中,并未使用到显示的close,虽然很多文章都推荐如此,不过在我的程序中,可能因为程序本身比较简单,要求不高,所以并未造成什么影响。)

3,创建Socket

创建Socket

java在包javanet中提供了两个类Socket和ServerSocket,分别用来表示双向连接的客户端和服务端。这是两个封装得非常好的类,使用很方便。其构造方法如下:

Socket(InetAddress address, int port);

Socket(InetAddress address, int port, boolean stream);

Socket(String host, int prot);

Socket(String host, int prot, boolean stream);

Socket(SocketImpl impl)

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

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

ServerSocket(int port);

ServerSocket(int port, int backlog);

ServerSocket(int port, int backlog, InetAddress bindAddr)

Socket client = new Socket("127001", 80);

ServerSocket server = new ServerSocket(80);

在创建socket时如果发生错误,将产生IOException,在程序中必须对之作出处理。所以在创建Socket或ServerSocket是必须捕获或抛出例外。

以上就是关于TCP及Socket全部的内容,包括:TCP及Socket、请教怎样发送socket请求包,并获得返回数据、C#中如何控制socket最大连接数等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/9726065.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-01
下一篇 2023-05-01

发表评论

登录后才能评论

评论列表(0条)

保存