Accept是又产生一个Socket端口吗?
要写网络程序就必须用Socket,这是程序员都知道的。而且,面试的时候,我们也会问对方会不会Socket编程?一般来说,很多人都会说,Socket编程基本就是listen,accept以及send,write等几个基本的操作。是的,就跟常见的文件操作一样,只要写过就一定知道。
对于网络编程,我们也言必称TCP/IP,似乎其它网络协议已经不存在了。对于TCP/IP,我们还知道TCP和UDP,前者可以保证数据的正确和可靠性,后者则允许数据丢失。最后,我们还知道,在建立连接前,必须知道对方的IP地址和端口号。除此,普通的程序员就不会知道太多了,很多时候这些知识已经够用了。最多,写服务程序的时候,会使用多线程来处理并发访问。
我们还知道如下几个事实:
1.一个指定的端口号不能被多个程序共用。比如,如果IIS占用了80端口,那么Apache就不能也用80端口了。
2.很多防火墙只允许特定目标端口的数据包通过。
3.服务程序在listen某个端口并accept某个连接请求后,会生成一个新的socket来对该请求进行处理。
于是,一个困惑了我很久的问题就产生了。如果一个socket创建后并与80端口绑定后,是否就意味着该socket占用了80端口呢?如果是这样的,那么当其accept一个请求后,生成的新的socket到底使用的是什么端口呢(我一直以为系统会默认给其分配一个空闲的端口号)?如果是一个空闲的端口,那一定不是80端口了,于是以后的TCP数据包的目标端口就不是80了--防火墙一定会阻止其通过的!实际上,我们可以看到,防火墙并没有阻止这样的连接,而且这是最常见的连接请求和处理方式。我的不解就是,为什么防火墙没有阻止这样的连接?它是如何判定那条连接是因为connet80端口而生成的?是不是TCP数据包里有什么特别的标志?或者防火墙记住了什么东西?
后来,我又仔细研读了TCP/IP的协议栈的原理,对很多概念有了更深刻的认识。比如,在TCP和UDP同属于传输层,共同架设在IP层(网络层)之上。而IP层主要负责的是在节点之间(End to End)的数据包传送,这里的节点是一台网络设备,比如计算机。因为IP层只负责把数据送到节点,而不能区分上面的不同应用,所以TCP和UDP协议在其基础上加入了端口的信息,端口于是标识的是一个节点上的一个应用。除了增加端口信息,UPD协议基本就没有对IP层的数据进行任何的处理了。而TCP协议还加入了更加复杂的传输控制,比如滑动的数据发送窗口(Slice Window),以及接收确认和重发机制,以达到数据的可靠传送。不管应用层看到的是怎样一个稳定的TCP数据流,下面传送的都是一个个的IP数据包,需要由TCP协议来进行数据重组。
所以,我有理由怀疑,防火墙并没有足够的信息判断TCP数据包的更多信息,除了IP地址和端口号。而且,我们也看到,所谓的端口,是为了区分不同的应用的,以在不同的IP包来到的时候能够正确转发。
TCP/IP只是一个协议栈,就像操作系统的运行机制一样,必须要具体实现,同时还要提供对外的操作接口。就像操作系统会提供标准的编程接口,比如Win32编程接口一样,TCP/IP也必须对外提供编程接口,这就是Socket编程接口--原来是这么回事啊!
在Socket编程接口里,设计者提出了一个很重要的概念,那就是socket。这个socket跟文件句柄很相似,实际上在BSD系统里就是跟文件句柄一样存放在一样的进程句柄表里。这个socket其实是一个序号,表示其在句柄表中的位置。这一点,我们已经见过很多了,比如文件句柄,窗口句柄等等。这些句柄,其实是代表了系统中的某些特定的对象,用于在各种函数中作为参数传入,以对特定的对象进行操作--这其实是C语言的问题,在C++语言里,这个句柄其实就是this指针,实际就是对象指针啦。
现在我们知道,socket跟TCP/IP并没有必然的联系。Socket编程接口在设计的时候,就希望也能适应其他的网络协议。所以,socket的出现只是可以更方便的使用TCP/IP协议栈而已,其对TCP/IP进行了抽象,形成了几个最基本的函数接口。比如create,listen,accept,connect,read和write等等。
现在我们明白,如果一个程序创建了一个socket,并让其监听80端口,其实是向TCP/IP协议栈声明了其对80端口的占有。以后,所有目标是80端口的TCP数据包都会转发给该程序(这里的程序,因为使用的是Socket编程接口,所以首先由Socket层来处理)。所谓accept函数,其实抽象的是TCP的连接建立过程。accept函数返回的新socket其实指代的是本次创建的连接,而一个连接是包括两部分信息的,一个是源IP和源端口,另一个是宿IP和宿端口。所以,accept可以产生多个不同的socket,而这些socket里包含的宿IP和宿端口是不变的,变化的只是源IP和源端口。这样的话,这些socket宿端口就可以都是80,而Socket层还是能根据源/宿对来准确地分辨出IP包和socket的归属关系,从而完成对TCP/IP协议的操作封装!而同时,放火墙的对IP包的处理规则也是清晰明了,不存在前面设想的种种复杂的情形。
明白socket只是对TCP/IP协议栈操作的抽象,而不是简单的映射关系,这很重要!
分享到:
相关推荐
在C#中实现Socket端口复用是一项关键的网络编程技术,它允许一个TCP或UDP端口在同一时间处理多个连接请求。端口复用技术在高并发、资源有限的环境中尤其重要,因为它可以提高服务器的效率,减少系统资源的消耗。在...
Socket,又称为套接字,是网络通信中的一个抽象接口,它允许应用程序通过Internet进行双向通信。在操作系统中,Socket接口提供了丰富的函数或方法,使得开发者能够构建网络应用,如服务器和客户端。 端口,是网络层...
下面我们将深入探讨如何在Windows服务中创建一个使用Socket的服务端口。 首先,我们需要了解Windows服务的基本结构。Windows服务通过`System.ServiceProcess`命名空间中的类来实现,如`ServiceBase`作为基础服务类...
本示例涉及的是一个Java实现的Socket程序,它能够实现“一对多”端口转发功能,这意味着本地的一个端口可以接收数据并将其转发到多个远程服务器的不同端口上。这种技术在诸如负载均衡、数据分发或安全代理等场景中...
总的来说,构建一个Socket端口监控程序是一项复杂的任务,需要深入理解网络编程、操作系统、数据处理和分析等多个领域的知识。`RawSocket`这个文件可能包含了实现此类程序所需的源代码或库,可供开发者参考和学习。
在这个示例代码中,我们使用了 sockaddr_in 结构体来设置服务器端的地址和端口,然后使用 socket 函数创建一个 Socket,接着使用 bind 函数将本地地址绑定到所创建的套接字上,最后使用 listen 函数对端口进行监听。...
- 在多线程或多进程模型中,通常主进程或主线程负责监听连接请求,一旦`accept`函数返回一个已建立连接的套接字,就创建一个新的子进程或子线程来处理该连接。 2. **并发处理** - 对于高并发场景,可以使用事件...
`accept`函数是服务器端处理客户端连接请求的核心方法之一,其主要作用是从内核中取出已经建立的客户端连接,并返回一个用于后续通信的新套接字。该函数定义如下: ```c #include <sys/socket.h> int accept(int ...
2. 绑定套接字:将一个或多个SOCKET句柄与完成端口关联起来,这样来自这些套接字的I/O事件就会被提交到完成端口。 3. 设置非阻塞模式:通过`ioctlsocket`或`setsockopt`函数将套接字设置为非阻塞模式,这样当调用`...
4. 接受连接:当有客户端连接时,调用accept()函数,返回一个新的Socket用于与该客户端进行通信。 5. 读写数据:通过新的Socket接收和发送数据。 6. 关闭连接:完成通信后,关闭Socket。 在描述中提到的"同时支持多...
标题中的"20120307_socket端口重定向(python示例)1"表明这是一个关于Python中实现socket端口重定向的教程,日期可能是发布时的时间。描述指出,场景是在端口12345上有一个文件共享服务,而目标是使用户能够通过8000...
Socket,又称为套接字,是网络编程中的一个抽象概念,它允许程序在互联网上与其他程序进行数据交换。在TCP/IP协议栈中,Socket接口提供了标准的API,开发者可以使用这些API创建客户端和服务器,实现数据的双向传输。...
在C/S模式下,服务器端创建一个Socket监听特定的IP地址和端口号,等待客户端连接;客户端则通过Socket向服务器发起连接请求,一旦连接建立,双方就可以通过Socket交换数据。 在C语言中实现Socket编程,通常需要以下...
- `Socket(String host, int port)`: 创建一个与指定主机和端口连接的Socket。 - `getInputStream()`: 获取输入流,用于读取远程系统发送的数据。 - `getOutputStream()`: 获取输出流,用于向远程系统发送数据。 ...
每个TCP连接都由一个唯一的四元组标识:源IP地址、源端口号、目标IP地址和目标端口号。服务器端通常固定目标IP地址和端口号,而客户端的源IP和端口会在每次连接时动态分配。 TCP端口监听的过程大致分为以下几个步骤...
标题提到的"单线程实现同时监听多个端口"是一种优化技术,它避免了为每个端口创建一个单独的线程,从而减少了系统资源的消耗。这种技术主要依赖于Windows的IO完成端口(I/O Completion Ports, IOCP)机制,它能高效地...
4. 接受连接:当有客户端请求连接时,`accept()`函数会返回一个新的Socket句柄,用于处理这个连接。 5. 数据传输:通过新创建的Socket句柄,服务器与客户端进行`read()`和`write()`操作,交换数据。 6. 关闭连接:...
监听端口意味着程序已经准备好接收来自客户端的连接,一旦有连接请求到达,服务器端就会调用accept()函数来接受这个连接,并创建一个新的Socket用于处理后续的数据传输。 “程序对发”则指的是两个程序(通常是...
在这个场景下,"完成端口IOCP Socket DELPHI控件"可能是一个设计用于简化IOCP和Socket编程的用户界面组件,使得开发者能够更方便地在DELPHI应用中利用IOCP机制进行网络通信。 `IOCPSocket.dcr`是一个DELPHI的资源...
本文将深入探讨如何使用TCP协议结合完成端口来构建一个Socket应用。 首先,理解TCP协议至关重要。TCP(Transmission Control Protocol)是一种面向连接、可靠的传输协议,它确保数据包按照顺序发送,并且通过确认...