TCP(传输控制协议)简介:面向连接、可靠的传输层协议

TCP简介

TCP(传输控制协议)简介:面向连接、可靠的传输层协议

TCP(传输控制协议传输控制协议)是一个连接的,可靠的,基于字节的传输层通信协议,该协议由IETF RFC 793定义。在简化的计算机网络OSI模型中,它完成了由传输的第四层指定的函数层。用户数据报协议(UDP,下一个博客将实现)是同一层中的另一个重要的传输协议。在Internet协议套件中,TCP层是位于IP层和应用程序层下方的中间层。不同主机的应用层通常需要可靠性和管道,但是IP层没有提供此类流机制,而是提供不可靠的软件包交换。

该应用层被发送到由网络传输的8 -bit Bytes表示的数据流的TCP层,然后将带有数据流量分区的TCP段发送到适当的长度(通常是连接到网络的数据链路层的数据链路层网络连接到最大传输单元(MTU)的计算机限制)。之后,TCP将传递到IP层,并通过网络将软件包传输到接收实体的TCP层。为了确保丢失数据包,每个袋子都会为TCP提供一个序列号。同时,序列号还保证按顺序接收到接收器实体的数据包。然后寄回接收端实体已成功收到的相应确认(ACK);如果在合理的回合延迟(RTT)损失中未确认发送端实体,则将重新分配。 TCP使用验证和功能来测试数据是否错误。发送和接收时会计算验证。

Java插座简介

SO符合的套接字通常称为“套接字”,用于描述IP地址和端口。它是通信链的手柄。应用程序通常通过“套接字”向网络发送请求或响应网络请求。

以J2SDK-1.3为例,套接字和serversocket类库位于java.net软件包中。服务器端用于服务器端,并在设置网络连接时使用插座。当连接成功时,将在应用程序的两端生成套接字实例,以操作此实例以完成所需的会话。对于网络连接,插座是相等的,没有区别。它不会生成不同的级别,因为它在服务器上或客户端上。无论是插座还是求服务,他们的工作都是通过socketimpl类及其子类完成的。

重要的插座API:

Java.net.socket继承在Java.lang.Object中。有八个构造函数。没有多少方法。下面介绍了三种最常见的方法。其他方法可以看到JDK-1.3文档。

接受方法用于生成“阻止”,直到它收到连接并返回客户端的套接字对象实例为止。 “阻塞”是一个术语,该术语使该程序暂时运行在此处,直到生成会话,然后该程序继续;通常,“阻止”是由周期产生的。

GetInputStream方法在返回InputStram对象实例时获得网络连接输入。

GetOutputStream方法的另一端将是输入的,并且同一时间返回了输出流对象实例。

注意:其中,getInputStream和getOutputStream方法将生成一个IOException,必须捕获,因为它们返回流对象,通常由另一个流对象使用。

SocketImpl简介

由于SocketImpl类及其子类都可以进行套接字和serversocket,因此,您必须将其引入。

抽象类SocketImpl是实际实现该类型的所有类的通用 - 可使用超类。可以使用创建客户端和服务器插座。

请参阅特定的JDK:

由于它是超类的特定代码的实现,或者查看下面的插座

TCP编程'构造函数serversocket

对于特定的API,请参见:

施工方法:

serversocket()〜创建一个非固定服务器套接字。

serversocket(int端口)〜创建一个绑定到特定端口的服务器套接字。

serversocket(int端口,int积压)〜使用指定的积压量来创建服务器套接字并将其绑定到指定的本地端口号。

serversocket(int端口,int积压,inetAddress bindaddr)〜使用指定的端口,收听积压,然后创建以绑定到本地IP地址的服务器。

1.1绑定端口

除了第一个没有参数的构造方法外,其他结构方法将将服务器绑定到特定端口。该端口具有指定的参数端口。例如,以下代码创建了一个绑定到端口80的服务器:

      ServerSocket serverSocket = new ServerSocket(80);  

如果在运行时无法将其束缚到端口80,则以上代码将抛出IOEXCEPTION。更确切地说,是抛出bindException。这是IOException的子类。 BindException通常是由以下原因引起的:

该端口已被其他服务器进程所占据;在某些操作系统中,如果服务器程序不作为超级用户运行,则操作系统不允许服务器绑定到1-1023之间的端口。

如果参数端口设置为0,则意味着操作系统将为服务器分配任意便携式端口。具有操作系统的端口也称为匿名端口。对于大多数服务器,将不使用匿名端口使用一个清晰​​的端口。由于客户程序需要提前了解服务器端口,因此易于访问服务器。

1.2设置客户连接请求队列的长度

  当服务器进程运行时, 可能会同时监听到多个客户的连接请求. 例如, 每当一个客户进程执行以下代码:

     Socket socket = new Socket("www.javathinker.org", 80); 

这意味着在远程主机的80端口上,听到了客户的连接请求。管理客户连接请求的任务由操作系统完成。操作系统将这些连接请求存储在高级队列中。许多。操作系统限制了队列的最大长度,通常为50。从队列中获取连接请求,以便队列可以在队列不在空缺位置之外时继续添加新的连接请求。

对于客户流程,如果将其发出的连接请求添加到服务器的请求连接队列中,则意味着客户与服务器之间的连接已成功建立。客户流程正常从套接字构造函数返回。拒绝,插座构造函数将抛出ConnectionXception。

提示:创建绑定端口的服务器过程后,当客户进程的套接字结构方法成功返回时,这意味着客户过程的连接请求将添加到服务器进程的请求连接队列中。尽管客户端成功地返回了插座对象,但尚未遵循它。服务器过程形成通信线路。必须通过ServerSocket的Access()方法将服务器进程从连接队列中取出连接队列,以及返回套接字对象后,服务器进程的套接字对象以使用客户端的套接字形成通信行目的。

serversocket构造方法的积压参数用于显示连接请求队列的长度,该长度将涵盖由操作系统限制队列的最大长度。最大长度:

积压参数的值大于操作系统限制队列的最大长度;积压参数的值小于或等于0;

serversocket构造函数中没有积压参数。

以下client.java和server.java用于演示服务器连接请求队列的特征。

client.java

import java.net.Socket;
public class Client {
 public static void main(String[] args) throws Exception{
  final int length = 100;
  String host = "localhost";
  int port = 1122;
  Socket[] socket = new Socket[length];
  for(int i = 0;inew Socket(host,port);
   System.out.println("第"+(i+1)+"次连接成功!");
  }
  Thread.sleep(3000);
  for(int i=0;i

server.java

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
 private int port = 1122;
 private ServerSocket serverSocket;
 public Server() throws Exception{
  serverSocket = new ServerSocket(port,3);
  System.out.println("服务器启动!");
 }
 public void service(){
  while(true){
   Socket socket = null;
   try {
    socket = serverSocket.accept();
    System.out.println("New connection accepted "+
      socket.getInetAddress()+":"+socket.getPort());
   } catch (IOException e) {
    e.printStackTrace();
   }finally{
    if(socket!=null){
     try {
      socket.close();
     } catch (IOException e) {
      e.printStackTrace();
     }
    }
   }
  }
 }
 public static void main(String[] args) throws Exception{
  Server server = new Server();
  Thread.sleep(60000*10);
  server.service();
 }
} 

  Client 试图与 Server 进行 100 次连接. 在 Server 类中, 把连接请求队列的长度设为 3. 这意味着当队列中有了 3 个连接请求时, 如果Client 再请求连接, 就会被 Server 拒绝.  下面按照以下步骤运行 Server 和 Client 程序.

⑴仅在服务器中创建一个serversocket对象。构造方法中指定的监视端口的长度为1122,连接请求队列的长度为3。构造构造函数后,服务器程序将睡眠10分钟,并且serversocket.acccept.acccept()方法。这意味着队列中的连接请求将永远不会被取出。运行服务器程序和客户端程序后,客户端程序的打印结果如下:

第一个连接成功

第二个连接成功

成功的连接

线程“ main” java.net.connectionxception中的异常:连接:连接

………………。

从上面打印的结果来看,可以看出,在成功建立客户端和服务器之后,由于服务器团队已满,因此无法再创建其余连接。

构造与服务器中⑴⑴相同的serverversocket的对象。服务器程序没有睡觉。在整个循环中,连续执行serversocket.accept()方法。新连接请求的打印结果。客户端程序的打印结果如下:

第一个连接成功

第二个连接成功

成功的连接

.............. ..

第100个连接成功

从上面的打印结果可以看出,目前,客户端可以成功建立与服务器的100个连接。 (随时随地的循环太快了。如果太慢,队列的连接请求的速度比连接请求的速度慢。如果您无法成功连接)

1.3设置绑定的IP地址

如果主机在默认值中只有一个IP地址,则服务器程序被绑定到IP地址。 serversocket serversocket的第四个构造函数(int端口,int积压,intetAddress bingaddr)具有BINDADDR参数,该参数明确指定服务器绑定IP地址,该构造函数适用于具有多个IP地址的主机。假设主机有两张网卡,一张网卡用于连接到Internet,IP为222.67.5.94,并且使用网卡连接到连接连接到连接连接连接连接的连接。本地LAN,IP地址为192.168.3.4。如果仅在本地LAN中的客户访问服务器,则可以创建serverSocket如下:

serversocket serverSocket = new serversocket(8000,10,inetaddress.getByName

1.4默认结构方法的作用

serversocket具有无参数的默认构造函数。该方法创建的serversocket不会绑定到任何端口。接下来,您需要将bind()方法绑定到特定端口。

该默认构造函数的目的是允许服务器在绑定到特定端口之前为serversocket设置一些选项。因为一旦服务器绑定到特定端口,就无法更改某些选项。例如:so_reuseaddr选项

  在以下代码中, 先把 ServerSocket 的 SO_REUSEADDR 选项设为 true, 然后再把它与 8000 端口绑定:

 ServerSocket serverSocket = new ServerSocket();
 serverSocket.setReuseAddress(true); //设置 ServerSocket 的选项
 serverSocket.bind(new InetSocketAddress(8000));  //与8000端口绑定

如果以上程序代码更改为:

  ServerSocket serverSocket = new ServerSocket(8000);
  serverSocket.setReuseAddress(true);//设置 ServerSocket 的选项

然后,serversocket.setReuseadDress(true)方法没有任何效果,因为必须在服务器绑定端口之前设置SO_REUSEADDDR选项。

多线程示例

客户:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
/*
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        try {
            //1.创建客户端Socket,指定服务器地址和端口
            Socket socket=new Socket("localhost", 8888);
            //2.获取输出流,向服务器端发送信息
            OutputStream os=socket.getOutputStream();//字节输出流
            PrintWriter pw=new PrintWriter(os);//将输出流包装为打印流
            pw.write("用户名:whf;密码:789");
            pw.flush();
            socket.shutdownOutput();//关闭输出流
            //3.获取输入流,并读取服务器端的响应信息
            InputStream is=socket.getInputStream();
            BufferedReader br=new BufferedReader(new InputStreamReader(is));
            String info=null;
            while((info=br.readLine())!=null){
                System.out.println("我是客户端,服务器说:"+info);
            }
            //4.关闭资源
            br.close();
            is.close();
            pw.close();
            os.close();
            socket.close();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

服务器:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/*
 * 基于TCP协议的Socket通信,实现用户登陆
 * 服务器端
 */
public class Server {
    public static void main(String[] args) {
        try {
            //1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口
            ServerSocket serverSocket=new ServerSocket(8888);
            Socket socket=null;
            //记录客户端的数量
            int count=0;
            System.out.println("***服务器即将启动,等待客户端的连接***");
            //循环监听等待客户端的连接
            while(true){
                //调用accept()方法开始监听,等待客户端的连接
                socket=serverSocket.accept();
                //创建一个新的线程
                ServerThread serverThread=new ServerThread(socket);
                //启动线程
                serverThread.start();
                count++;//统计客户端的数量
                System.out.println("客户端的数量:"+count);
                InetAddress address=socket.getInetAddress();
                System.out.println("当前客户端的IP:"+address.getHostAddress());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

服务器处理类:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
/*
 * 服务器线程处理类
 */
public class ServerThread extends Thread {
    // 和本线程相关的Socket
    Socket socket = null;
    public ServerThread(Socket socket) {
        this.socket = socket;
    }
    //线程执行的操作,响应客户端的请求
    public void run(){
        InputStream is=null;
        InputStreamReader isr=null;
        BufferedReader br=null;
        OutputStream os=null;
        PrintWriter pw=null;
        try {
            //获取输入流,并读取客户端信息
            is = socket.getInputStream();
            isr = new InputStreamReader(is);
            br = new BufferedReader(isr);
            String info=null;
            while((info=br.readLine())!=null){//循环读取客户端的信息
                System.out.println("我是服务器,客户端说:"+info);
            }
            socket.shutdownInput();//关闭输入流
            //获取输出流,响应客户端的请求
            os = socket.getOutputStream();
            pw = new PrintWriter(os);
            pw.write("欢迎您!");
            pw.flush();//调用flush()方法将缓冲输出
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            //关闭资源
            try {
                if(pw!=null)
                    pw.close();
                if(os!=null)
                    os.close();
                if(br!=null)
                    br.close();
                if(isr!=null)
                    isr.close();
                if(is!=null)
                    is.close();
                if(socket!=null)
                    socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

你可能想看:
« 上一篇
下一篇 »

相关推荐

java中什么是冒泡,冒泡算法

2026年09月06日

27阅读

java中冒号,java双冒号

2026年09月06日

26阅读

java中的->,java中的是什么意思

2026年09月06日

24阅读

java中的super用法,Java中super的说明

2026年09月06日

28阅读

java中反射的应用,java中反射的应用场景

2026年09月06日

26阅读

java中开关的定义,Java关键字有哪些

2026年09月06日

26阅读