大家好,今天给各位分享如何区分同一端口上的不同套接字的一些知识,其中也会对进行解释,文章篇幅可能偏长,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在就马上开始吧!
Accept()生成的Socket端口号是多少?
编写网络程序,必须使用Sockets。这是程序员都知道的。面试的时候我们也会问对方是否懂socket编程。很多人会说Socket编程基本上就是由监听、接受、发送和写入组成。几个基本操作与普通文件操作相同。只要你写过它们,你就会认识它们。
对于网络编程,我们必须称之为TCP。好像其他的网络协议已经不存在了。对于TCP,我们还知道UDP。前者可以保证数据的准确性和可靠性,后者允许数据丢失。最后我们还知道,在建立连接之前,必须知道对方的IP地址和端口号。另外,普通程序员不会知道太多。在许多情况下,这些知识就足够了。最多在编写服务程序时使用多线程。并发访问。
我们还知道以下事实
1. 指定的端口号不能被多个应用程序共享。例如,如果IIS占用80端口,那么APACHE就不能使用该端口。
2. 许多防火墙只允许来自特定目的端口的数据包通过。
3、服务程序监听某个端口并接受连接请求后,会生成一个新的socket来处理该请求。
那么一个困扰我很久的问题就出现了。如果创建了一个socket并绑定了80端口,那么是否意味着该socket占用了80端口?
如果是这种情况,那么当它接受请求时,新套接字使用哪个端口? (我一直以为系统会默认给它分配一个空闲端口号)
如果是空闲端口号,那么一定不是80端口,所以以后的TCP数据包的端口肯定不是80——防火墙会阻止它通过。
事实上,我们可以看到防火墙并没有阻止这样的连接,而这也是最常见的连接请求和处理方式。我不明白的是为什么防火墙不阻止这样的连接。它如何判断连接是因为connect80端口生成的呢? TCP数据包中是否有什么特殊标记,或者防火墙是否记住了什么?
后来我仔细阅读了TCP/IP协议栈的原理,对很多概念有了更深入的理解。例如,TCP和UDP都属于传输层,共同假设在IP层之上,而IP层主要负责节点之间的通信。对于数据包的传输来说,这里的节点是网络设备,比如计算机。由于IP只负责向节点发送数据,无法区分上述不同的应用,所以TCP和UDP在协议中增加了端口。信息,端口标识节点上的应用程序,并处理添加端口信息。 UDP协议基本不处理IP层的数据,TCP协议还增加了更复杂的传输控制,比如滑动数据传输。窗口,以及接受确认和重传机制,实现数据的可靠传输。无论应用层看到什么样的稳定的TCP数据流,下面传输的都是一个接一个的IP数据包,需要TCP协议进行处理。执行数据重组。
TCP/IP只是一个协议栈。就像操作系统的运行机制一样,必须具体实现。同时必须提供外部操作接口。就像操作系统提供标准的编程接口,如Win32编程接口一样,TCP、IP也必须向外界提供编程接口。这就是Socket 编程接口- 就是这样。
在Socket编程接口中,设计者提出了一个非常重要的概念,那就是socket。这个套接字与文件句柄非常相似。事实上,在BSD系统中,它与文件句柄存储在同一个进程句柄中。这个socket实际上是一个序列号,表明它在句柄表中的位置。我们见过很多这样的情况,比如文件句柄、窗口句柄等,这些句柄实际上代表了系统中某些特定的对象,在各种函数中作为参数来操作特定的对象。 —— 这其实是C语言的问题。在C++语言中,this句柄其实就是this指针,它实际上是一个对象指针。
现在我们知道socket与TCP/IP没有必然的关系。设计Socket编程接口时,希望它也能适配其他网络协议。所以socket的出现只是让TCP/IP协议栈的使用变得更加简单。它对TCP/IP进行了抽象,形成了几个基本的功能接口。例如创建、监听、接受、连接、读写等。
需要明白的是,socket只是TCP/IP协议栈操作的抽象,并不是简单的映射关系!
昨天和朋友聊了网络编程。关于Socket,我在这里写下我个人的一些理解:)
程序中可以创建Socket,分为普通Socket和原始Socket两种。
1:普通Socket是TCP/IP协议栈中传输层操作的编程接口(一种API)。
有面向连接的流式套接字(SOCK_STREAM),它是TCP的一个应用;
没有连接数据包的socket(SOCK_DGRAM),这是UDP方式的应用。
关于普通Sockets,我曾经有过一个模糊的问题。在多线程情况下,服务器监听某个端口(假设8080)后,每次接受客户端连接都会生成一个新的Socket。那么这些新生成的Socket的端口是什么呢?程序中肯定没有指定,所以应该有两种可能,1:生成随机端口。 2:仍然是8080端口。仔细想想,第一个假设似乎是不可能的。防火墙很可能会阻止来自这些随机端口的数据包。然后还有第二个假设,服务器端口仍然是8080。但这颠覆了我原来的理解,即“如果一个端口被某个程序占用,其他程序就无法使用该端口”。我认为最有可能的原因是范围不同:程序之间不能使用相同的端口,但程序内不同的Socket仍然可以使用相同的端口。因此,为了使“客户端在同一端口(8080)上向服务器发送的来自不同线程(即不同Socket连接)的数据包能够被区分和组合”,必须有一个区分特征来区分来自不同线程的数据包。连接。即传输层头中的源端口,即Socket连接中客户端的端口。综上所述,这种情况下,传输层头中的源端口(客户端)将与生成的Socket不同,但接收端口将相同(服务器)。
文章中回答了很多问题,特别是“端口是用来区分不同的应用程序”。之前我也很困惑,多线程下每个线程建立连接的端口是否可以相同。另外,文章中说,每次接受连接时,都会获得一个新的套接字。这个表达并不完美。事实上,它不是一个新的套接字,而是客户端的套接字。这个socket中的IP和端口当然是客户端的IP和端口。表示accept客户端后,服务器使用哪个端口。
单个进程监听多个端口
单个进程创建多个套接字并绑定不同的端口(TCP 或UDP)。
多个进程监听同一端口
这可以通过fork创建子进程来实现,但其他情况则不行。
在多线程情况下,服务器监听某个端口后,每次接受客户端连接都会生成一个新的Socket。
新生成的Socket的端口是多少?
答案是服务器端口或监听端口。
进程之间不能使用相同的端口,但进程内的不同Socket可以使用相同的端口。
如何区分同一端口上Client向Server发送的不同Socket。
使用Client Socket端口来区分!
Socket是TCP/IP协议的网络接口。 Socket是TCP/IP协议操作的抽象。
客户端连接函数启动调用该函数的过程并准确返回三次握手。如果第三次握手成功则返回
服务器端三次握手后,内核调用accept函数。执行accept函数后,会生成一个新的socket来连接客户端。
Q: 编写TCP/SOCK_STREAM服务程序时,SO_REUSEADDR是什么意思?
A: 此套接字选项通知内核,如果端口繁忙但TCP 状态处于TIME_WAIT,则可以重用该端口。如果端口繁忙,
TCP状态处于其他状态,并且当重新使用该端口时,我仍然收到一条错误消息,指示“该地址已在使用中”。如果您的服务程序停止
如果你想立即重新启动,但新的套接字仍然使用相同的端口,SO_REUSEADDR选项非常有用。必须认识到,此时任何
意外数据的到来可能会导致服务程序响应混乱,但这只是一种可能性,实际上可能性很小。
端口复用最常见的用途是防止在服务器重启或者程序突然退出而系统没有释放端口时,之前绑定的端口被释放。这种情况下,如果设置了端口复用,则新启动的服务器进程可以直接绑定端口。如果不设置端口复用,绑定会失败,提示ADDR已被使用。 —— 那你就得等一下再试了,麻烦!
那么如何让sockfd_one和sockfd_two套接字都成功绑定到8000端口呢?这时候就需要复用端口。端口重用允许应用程序将n 个套接字绑定到一个端口而不会出现错误。
设置socket的SO_REUSEADDR选项来实现端口复用:
int opt=1;//sockfd是需要端口复用的socket setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *)opt, sizeof(opt)); SO_REUSEADDR可以在以下四种情况下使用。 (摘自《Unix网络编程》 第1 卷,UNPv1)
1、当有一个本地地址和端口相同的socket1处于TIME_WAIT状态,而你启动的程序的socket2需要占用该地址和端口时,你的程序就会使用这个选项。
2. SO_REUSEADDR允许在同一端口上启动同一服务器的多个实例(多个进程)。但每个实例绑定的IP地址不能相同。这种情况可以在多网卡或者IP Alias技术的机器上进行测试。
3、SO_REUSEADDR允许单个进程将同一个端口绑定到多个套接字,但每个套接字绑定的IP地址不同。这与2 非常相似,请参阅UNPv1 了解差异。
4. SO_REUSEADDR 允许重复绑定完全相同的地址和端口。但这仅适用于UDP 多播,不适用于TCP。
需要注意的是,绑定前必须调用端口复用函数,绑定到同一端口的所有套接字都必须被复用:
//sockfd_one和sockfd_two都必须设置端口复用//sockfd_one绑定bind之前,设置其端口复用int opt=1;setsockopt( sockfd_one, SOL_SOCKET,SO_REUSEADDR, (const void *)opt, sizeof(opt) ) ;err_log=绑定(sockfd_one, (struct sockaddr*)my_addr, sizeof(my_addr)); //sockfd_two绑定bind之前,设置其端口复用opt=1;setsockopt( sockfd_two, SOL_SOCKET,SO_REUSEADDR,(const void * )opt, sizeof(opt) );err_log=bind(sockfd_two, (struct sockaddr*)my_addr, sizeof (我的地址));端口多路复用允许应用程序将n 个套接字绑定到一个端口,而不会出现问题。同时这n个socket正常发送信息,没有问题。但是,并不是所有这些socket都能读取信息,只有最后一个socket会正常接收数据。
#include stdio.h#include stdlib.h#include string.h#include unistd.h#include sys/socket.h#include netinet/in.h#include arpa/inet.h#include pthread.h //线程1回调函数void *recv_one(void *arg){printf(‘============recv_one==============\n’);int sockfd=( int )arg;while(1){int recv_len;char recv_buf[512]=”;struct sockaddr_in client_addr;char cli_ip[INET_ADDRSTRLEN]=”;//INET_ADDRSTRLEN=16socklen_t cliaddr_len=sizeof(client_addr);recv_len=recvfrom ( sockfd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr*)client_addr, cliaddr_len);inet_ntop(AF_INET, client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);printf(‘\nip:%s ,port:%d\n’, cli_ip , ntohs(client_addr.sin_port));printf(‘sockfd_one===========data(%d):%s\n’,recv_len,recv_buf);} return NULL;} //线程2 回调函数void *recv_two(void *arg){printf(‘++++++++++recv_two++++++++++++++++\n’);int sockfd=(int )arg;while(1){int recv_len;char recv_buf [512 ]=”;struct sockaddr_in client_addr;char cli_ip[INET_ADDRSTRLEN]=”;//INET_ADDRSTRLEN=16socklen_t cliaddr_len=sizeof(client_addr);recv_len=recvfrom(sockfd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr *) client_addr, cliaddr_len);inet_ntop(AF_INET, client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);printf(‘\nip:%s ,port:%d\n’,cli_ip, ntohs(client_addr.sin_port));printf(‘sockfd_two @ @@ @@@@@@@@@@@ data(%d):%s\n’,recv_len,recv_buf);} 返回NULL;} int main(int argc, char *argv[]){int err_log ; ///////////////////////////sockfd_oneint sockfd_one;sockfd_one=套接字(AF_INET, SOCK_DGRAM, 0); //创建UDP套接字oneif(sockfd_one 0 ){perror(‘sockfd_one’);exit(-1);} //设置本地网络信息struct sockaddr_in my_addr;bzero(my_addr, sizeof(my_addr));my_addr.sin_family=AF_INET ;my_addr.sin_port=htons(8000) ;//端口为8000my_addr.sin_addr.s_addr=htonl(INADDR_ANY);//sockfd_one绑定bind之前,设置其端口复用int opt=1;setsockopt( sockfd_one, SOL_SOCKET, SO_REUSEADDR, (const void *)opt, sizeof(opt) ); //绑定,端口为8000err_log=bind(sockfd_one, (struct sockaddr*)my_addr, sizeof(my_addr));if(err_log !=0){perror(‘bind sockfd_one’);close( sockfd_one);exit(-1 );}//接收信息线程1pthread_t tid_one;pthread_create(tid_one, NULL, recv_one, (void *)sockfd_one);///////////////////////////sockfd_twoint sockfd_two;sockfd_two=套接字(AF_INET, SOCK_DGRAM, 0); //创建UDP套接字twoif(sockfd_two 0){perror(‘sockfd_two’);exit(-1);} //在sockfd_two绑定bind之前,设置其端口复用opt=1; setockopt( sockfd_two, SOL_SOCKET,SO_REUSEADDR, (const void *)opt, sizeof(opt) ); //新建socket sockfd_two,继续绑定8000端口,成功err_log=bind(sockfd_two, (struct sockaddr*)my_addr, sizeof(my_addr));if(err_log !=0){perror(‘bind sockfd_two’);close( sockfd_two);exit(-1);} //接收信息线程2pthread_t tid_two;pthread_create(tid_two, NULL, recv_two, (void *)sockfd_two);while(1){//让程序阻塞在这里,不结束NULL;}关闭(sockfd_one);关闭(sockfd_two); return 0;} 然后通过网络调试助手向该服务器发送数据。结果显示只有最后一个socket sockfd_two会正常接收数据。
一个连接的唯一标识是[服务器ip,服务器端口,客户端ip,客户端端口],也就是说。当操作系统从某个端口接收数据时,它会找到与这个唯一标识符匹配的端口生成的连接,并将信息传输到相应的缓冲区。
原创文章,作者:小su,如若转载,请注明出处:https://www.sudun.com/ask/202188.html
用户评论
仰望幸福
讲得真不错!一直困扰着我一个问题,就是怎么在同一个端口上实现不同的应用服务。这篇文章给出了清晰明了的解释,让我终于明白了 socket 如何实现这种分化的功能。
有19位网友表示赞同!
心已麻木i
对这个说法很认同,不同协议、不同应用的程序确实可以通过一些技术手段区分处理,就像你说的网络层和传输层就各自负责不同的工作。文章内容通俗易懂,帮助我更深入地理解了端口的概念和应用场景。
有5位网友表示赞同!
莫阑珊
这篇文章让我眼前一亮!以前一直以为同一个端口只能运行一个服务,看来我的想法有点狭隘。通过阅读,我意识到有很多技巧能够在同一端口上区分不同的 socket,例如使用不同的协议、数据包类型或者业务逻辑来进行处理。
有19位网友表示赞同!
心贝
我理解你的观点,但我想提出一个小疑问:如果在一个端口上有多个应用运行的情况下,会不会出现冲突?比如,两个应用同时发送数据到同一个端口时,如何避免混乱和数据丢失呢?
有14位网友表示赞同!
采姑娘的小蘑菇
同意作者的说法,不同的业务场景确实会需要利用同一端口进行区分处理。例如,一个服务器可能既要提供 HTTP 服务又要提供 WebSocket 服务,就可以通过不同的协议或数据包类型来实现这一点。但具体的技术细节还需要更深入的了解和实践才能掌握。
有19位网友表示赞同!
南初
对于网络编程来说,同一个端口运行多个服务确实是个比较常见的情况,因为这样做可以有效利用资源。但是,这同时也带来了很多挑战,需要设计合理的机制来确保每个服务都能正常运行而不产生冲突。
有9位网友表示赞同!
微信名字
我很想深入了解一下文章中提到的“进程隔离”、“socket 特征”等概念。我的理解是,它们应该是在同一端口下实现不同 socket 区分的重要技术手段,请问作者可以分享更多关于它们的具体的解释和应用案例吗?
有5位网友表示赞同!
艺菲
我觉得这篇博文写的很好,内容清晰易懂,能够帮助初学者迅速理解这个话题。尤其喜欢里面提到的“使用特定的头信息或数据包标志位来识别不同的 socket 类型”这种方式,很有实用意义。
有6位网友表示赞同!
夏至离别
文章的论点很有道理,但是我更倾向于将同一端口上的不同 socket 处理看作是一个系统级的设计问题,需要进行周密的规划和设计才能确保其稳定性和安全性。
有17位网友表示赞同!
暖栀
对于同一个端口如何区分不同的 Socket 这确实是一个很有意义的话题。这篇文章开阔了我的眼界,让我对网络编程有了更深层次的理解。我很期待看到更多关于这个话题的深入分析和探讨。
有20位网友表示赞同!
棃海
虽然我目前还没有真正使用到这种技术,但是我很能感受到作者想传达的信息–在复杂的网络环境中,如何巧妙地利用有限资源始终是个值得探索的问题。这篇文章让我对这一问题有了更清晰的认识。
有18位网友表示赞同!
你tm的滚
我一直不太明白这个概念,看了这篇博文终于明白了!原来同一端口下也可以运行不同的服务,只是需要通过一些技巧来区分不同的 Socket。作者的讲解非常详细清晰,受益匪浅!
有8位网友表示赞同!
糖果控
对于网络编程技术我比较熟悉 ,但是对同一端口如何区分不同 socket 还是第一次接触到这个说法。文章的内容让我了解到了很多新的知识点,非常有用!
有5位网友表示赞同!
太难
我觉得这篇文章写的不太全面,仅仅介绍了表面上的一些方式,并没有深入探讨一些复杂的场景下的解决方案,比如当多个服务同时处理来自同一 IP 地址的请求时如何避免冲突等。
有19位网友表示赞同!
你的眸中有星辰
我有一个疑问:使用这种方法区分 Socket 是否会带来额外的性能开销?毕竟需要加一些额外的标识信息和判断逻辑,会不会影响系统的效率呢?
有17位网友表示赞同!
从此我爱的人都像你
这篇文章对我来说意义不大,因为我的应用场景中压根不会用到同一端口运行多个服务的方案。我更关注的是如何提高一个服务的多线程处理能力和性能优化等内容。
有6位网友表示赞同!