分配端口号
时间:2022-05-02 19:40 | 分类: 句子大全 | 作者:一口Linux | 评论: 次 | 点击: 次
分配端口号
1.
我来回答你的问题:
1.服务器地址,一般都是在公网公开的网站地址,用来为用户提供服务的,一般都是使用公网地址,这样容易标示。
2.端口号是一种逻辑的概念,电脑上开每一个网络服务都会自动开启相应的TCP/UDP端口号(端口号还和协议有关),例如你打开网页,那么肯定会使用、sina.com等。IP和域名之间存在一定的对应关系。如果把IP地址类比成身份证号的话,那么域名就是你的姓名。一台拥有IP地址的主机可以提供许多服务,比如Web服务、FTP服务、SMTP服务等,这些服务完全可以通过1个IP地址来实现。那么,主机是怎样区分不同的网络服务呢?显然不能只靠IP地址,因为IP 地址与网络服务的关系是一对多的关系。实际上是通过“IP地址+端口号”来区分不同的服务的。
其实在网络中只能使用IP地址进行数据传输,所以在传输以前,需要把域名转换为IP,这个由称作DNS的服务器专门来完成。 所以在网络编程中,可以使用IP或域名来标识网络上的一台设备。
为了在一台设备上可以运行多个程序,人为的设计了端口(Port)的概念,类似的例子是公司内部的分机号码。规定一个设备有2^16个,也就是65536个端口,每个端口对应一个唯一的程序。每个网络程序,无论是客户端还是服务器端,都对应一个或多个特定的端口号。由于0-1024之间多被操作系统占用,所以实际编程时一般采用1024以后的端口号。
下面是一些常见的服务对应的端口:ftp:23,telnet:23,smtp:25,dns:53,/bbs/jsp/view.jsp?articleID=1459163
什么是“端口”?
在网络技术中,端口(Port)有好几种意思。集线器、交换机、路由 器的端口指的是连接其他网络设备的接口,如RJ-45端口、Serial端口等。我们 这里所指的端口不是指物理意义上的端口,而是特指TCP/IP协议中的端口,是逻 辑意义上的端口。
那么TCP/IP协议中的端口指的是什么呢?如果把IP地址比作一间房子 ,端口就是出入这间房子的门。真正的房子只有几个门,但是一个IP地址的端口 可以有65536个之多!端口是通过端口号来标记的,端口号只有整数,范围是从0 到65535。
端口有什么用呢?我们知道,一台拥有IP地址的主机可以提供许多服务,比如Web服务、FTP服务、SMTP服务等,这些服务完全可以通过1个IP地址来实现。那么,主机是怎样区分不同的网络服务呢?显然不能只靠IP地址,因为IP 地址与网络服务的关系是一对多的关系。实际上是通过“IP地址+端口号”来区 分不同的服务的。
需要注意的是,端口并不是一一对应的。比如你的电脑作为客户机访 问一台WWW服务器时,WWW服务器使用“80”端口与你的电脑通信,但你的电脑则 可能使用“3457”这样的端口,如图1所示。
按对应的协议类型,端口有两种:TCP端口和UDP端口。由于TCP和UDP 两个协议是独立的,因此各自的端口号也相互独立,比如TCP有235端口,UDP也 可以有235端口,两者并不冲突。
1.周知端口(Well Known Ports)
周知端口是众所周知的端口号,范围从0到1023,其中80端口分配给W WW服务,21端口分配给FTP服务等。我们在IE的地址栏里输入一个网址的时候( 比如.cn)是不必指定端口号的,因为在默认情况下WWW服务的端口 号是“80”。
网络服务是可以使用其他端口号的,如果不是默认的端口号则应该在 地址栏上指定端口号,方法是在地址后面加上冒号“:”(半角),再加上端口 号。比如使用“8080”作为WWW服务的端口,则需要在地址栏里输入“:8080”。
但是有些系统协议使用固定的端口号,它是不能被改变的,比如139 端口专门用于NetBIOS与TCP/IP之间的通信,不能手动改变。
2.动态端口(Dynamic Ports)
动态端口的范围是从1024到65535。之所以称为动态端口,是因为它一般不固定分配某种服务,而是动态分配。动态分配是指当一个系统进程或应用 程序进程需要网络通信时,它向主机申请一个端口,主机从可用的端口号中分配一个供它使用。当这个进程关闭时,同时也就释放了所占用的端口号。
怎样查看端口
一台服务器有大量的端口在使用,怎么来查看端口呢?有两种方式: 一种是利用系统内置的命令,一种是利用第三方端口扫描软件。
1.用“netstat -an”查看端口状态
在Windows 2000/XP中,可以在命令提示符下使用“netstat -an”查 看系统端口状态,可以列出系统正在开放的端口号及其状态.
2.用第三方端口扫描软件
第三方端口扫描软件有许多,界面虽然千差万别,但是功能却是类似 的。这里以“Fport” (可到/soft/cce下载)为例讲解。“Fport”在命令提示符下使用,运行结果 与“netstat -an”相似,但是它不仅能够列出正在使用的端口号及类型,还可 以列出端口被哪个应用程序使用.
6. 无线路由 端口号是
你可以使用1-65535端口,其中0-1023为固定端口,也就是知名端口,比如Telnet(端口号23)、FTP(端口号21),Http(端口号80)等,1024-65535为动态端口!
(1)知名端口(Well-Known Ports)
知名端口即众所周知的端口号,范围从0到1023,这些端口号一般固定分配给一些服务。比如21端口分配给FTP服务,25端口分配给SMTP(简单邮件传输协议)服务,80端口分配给HTTP服务,135端口分配给RPC(远程过程调用)服务等等。
(2)动态端口(Dynamic Ports)
动态端口的范围从1024到65535,这些端口号一般不固定分配给某个服务,也就是说许多服务都可以使用这些端口。只要运行的程序向系统提出访问网络的申请,那么系统就可以从这些端口号中分配一个供该程序使用。比如1024端口就是分配给第一个向系统发出申请的程序。在关闭程序进程后,就会释放所占用的端口号。
「TCP/UDP」一个端口号可以同时被两个进程绑定吗?
tcp/udp
一、1个端口号可以同时被两个进程绑定吗?
根据端口号的绑定我们分以下几种情况来讨论:
2个进程分别建立TCP server,使用同一个端口号88882个进程分别建立UDP server,使用同一个端口号88882个进程1个建立TCP server、1个建立UDP server,都使用端口号88881. 测试代码
我们首先编写两个简单的测试程序。
tcp.c
该程序仅仅创建tcp套接字并绑定端口号8888,没有accept建立连接操作,并且sleep(1000),让进程不要太快退出。
/*******服务器程序TCPServer.c************/#include<stdlib.h>#include<stdio.h>#include<errno.h>#include<string.h>#include<netdb.h>#include<sys/types.h>#include<netinet/in.h>#include<sys/socket.h>#include<pthread.h>#defineWAITBUF10#defineRECVBUFSIZE1024intmain(intargc,char*argv[]){intsockfd,new_fd,nbytes;structsockaddr_inserver_addr;structsockaddr_inclient_addr;intportnumber=8888;socklen_tsin_size;charhello[512];charbuffer[RECVBUFSIZE];/*端口号不对,退出*//*服务器端开始建立socket描述符*/if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){fprintf(stderr,"Socketerror:%s\n\a",strerror(errno));exit(1);}/*服务器端填充sockaddr结构*/bzero(&server_addr,sizeof(structsockaddr_in));server_addr.sin_family=AF_INET;/*自动填充主机IP*/server_addr.sin_addr.s_addr=htonl(INADDR_ANY);server_addr.sin_port=htons(portnumber);/*捆绑sockfd描述符进程+端口号+ip+socket*/if(bind(sockfd,(structsockaddr*)(&server_addr),sizeof(structsockaddr))==-1){fprintf(stderr,"Binderror:%s\n\a",strerror(errno));exit(1);}/*监听sockfd描述符*/if(listen(sockfd,WAITBUF)==-1){fprintf(stderr,"Listenerror:%s\n\a",strerror(errno));exit(1);}sleep(1000);//让程序不要这么快的退出close(sockfd);exit(0);}
udp.c
该程序仅仅创建udp套接字并绑定端口号8888,没有accept建立连接操作,并且sleep(1000),让进程不要太快退出.
#include<stdlib.h>#include<stdio.h>#include<errno.h>#include<string.h>#include<unistd.h>#include<netdb.h>#include<sys/socket.h>#include<netinet/in.h>#include<sys/types.h>#include<arpa/inet.h>#defineSERVER_PORT8888#defineMAX_MSG_SIZE1024intmain(void){intsockfd;structsockaddr_inaddr;/*服务器端开始建立socket描述符*/sockfd=socket(AF_INET,SOCK_DGRAM,0);if(sockfd<0){fprintf(stderr,"SocketError:%s\n",strerror(errno));exit(1);}/*服务器端填充sockaddr结构*/bzero(&addr,sizeof(structsockaddr_in));addr.sin_family=AF_INET;addr.sin_addr.s_addr=htonl(INADDR_ANY);addr.sin_port=htons(SERVER_PORT);/*捆绑sockfd描述符*/if(bind(sockfd,(structsockaddr*)&addr,sizeof(structsockaddr_in))<0){fprintf(stderr,"BindError:%s\n",strerror(errno));exit(1);}sleep(1000);close(sockfd);}
编译
gcctcp.c-otcpgccudp.c-oudp
2. 执行结果
1).2个进程分别建立TCP server
情况1执行结果
从结果可知,第二个进程绑定端口号8888绑定失败。
2).2个进程分别建立UDP server
情况2执行结果
从结果可知,第二个进程绑定端口号8888绑定失败。
3).1个建立TCP server、1个建立UDP server
情况3执行结果
用netstat命令查看信息。
netstat
从结果可知,该种情形,两个进程分别绑定成功。
3. 结果分析
由上述结果可知:TCP、UDP可以同时绑定一个端口8888,但是一个端口在同一时刻不可以被TCP或者UDP绑定2次。 原因如下:
tcp的端口不是物理概念,仅仅是协议栈中的两个字节;TCP和UDP的端口完全没有任何关系,完全有可能又有一种XXP基于IP,也有端口的概念,这是完全可能的;TCP和UDP传输协议监听同一个端口后,接收数据互不影响,不冲突。因为数据接收时时根据五元组**{传输协议,源IP,目的IP,源端口,目的端口}**判断接受者的。二、端口号的一些其他知识点
1. 端口号的作用
端口号可以用来标识同一个主机上通信的不同应用程序,端口号+IP地址就可以组成一个套接字,用来标识一个进程。
2. 端口号的应用场景
在TCP/IP协议中,用“源IP地址”,“目的IP地址”,“源端口号”,“目的端口号”,协议号(IP协议的协议号为4,TCP的协议号为6)这样的一个五元组来标识一个通信,通信的双方在发送消息时,消息的头部会带着这样的五元组。
3. 端口范围划分
(1)0~1023:知名端口号,是留着备用的,一把都是用于协议,例如HTTP、FTP、SSH ;
(2)1024~65535:是操作系统动态分配的端口号,客户端程序的端口号,就是由操作系统从这个范围来分配的,在TCP与UDP的套接字通信中,客户端的端口号就是在此范围中。
4. 知名的端口号与端口号对应的服务器
比如:
HTTP服务器:80FTP服务器:21
ps:FTP有一个控制连接和一个数据连接,所以FTP是有两个端口号的,控制连接的端口号是21,数据连接的端口号是20,但是如果FTP的端口号默认是21,如果指明FTP有两个端口号的话,那就是21和20,否则FTP服务器的端口号就是21
TELNET服务器:23SSH服务器:22HTTPS:443WEB服务器:25
5. 在linux中如何查看知名端口号?
cat/etc/services
6. 一个进程是否可以bind多个端口号?
可以
因为一个进程可以打开多个文件描述符,而每个文件描述符都对应一个端口号,所以一个进程可以绑定多个端口号。
Linux内核会给每一个socket分配一个唯一的文件描述符,进程通过该文件描述符来区分对应的套接字。
7. 一个端口号是否可以被多个进程绑定?
同种协议通常不可以,但有一种情况可以。
ps:如果进程先绑定一个端口号,然后在fork一个子进程,这样的话就可以是实现多个进程绑定一个端口号,但是两个不同的进程绑定同一个端口号是不可以的。
三、SO_REUSEADDR有什么用处和怎么使用?
当两个socket的address和port相冲突,而我们又想重用地址和端口,则旧的socket和新的socket都要已经被设置了SO_REUSEADDR特性,只有两者之一有这个特性还是有问题的。
SO_REUSEADDR可以用在以下四种情况下。(摘自《Unix网络编程》卷一,即UNPv1)
当有一个有相同本地地址和端口的socket1处于TIME_WAIT状态时【4次握手】,而你启动的程序的socket2要占用该地址和端口,你的程序就要用到该选项。一般来说,一个端口释放后会等待两分钟之后才能再被使用,SO_REUSEADDR是让端口释放后立即就可以被再次使用。
SO_REUSEADDR用于对TCP套接字处于TIME_WAIT状态下的socket,才可以重复绑定使用。server程序总是应该在调用bind()之前设置SO_REUSEADDR套接字选项。TCP,先调用close()的一方会进入TIME_WAIT状态。
4次握手顺序见下图:
4次握手
SO_REUSEADDR允许同一port上启动同一服务器的多个实例(多个进程)。但每个实例绑定的IP地址是不能相同的。在有多块网卡或用IP Alias技术的机器可以测试这种情况。SO_REUSEADDR允许单个进程绑定相同的端口到多个socket上,但每个socket绑定的ip地址不同。这和2很相似,区别请看UNPv1。SO_REUSEADDR允许启动一个监听服务器并捆绑其众所周知端口,即使以前建立的将此端口用做他们的本地端口的连接仍存在。这通常是重启监听服务器时出现,若不设置此选项,则bind时将出错。
SO_REUSEADDR允许在同一端口上启动同一服务器的多个实例,只要每个实例捆绑一个不同的本地IP地址即可。对于TCP,我们根本不可能启动捆绑相同IP地址和相同端口号的多个服务器。
SO_REUSEADDR允许单个进程捆绑同一端口到多个套接口上,只要每个捆绑指定不同的本地IP地址即可。这一般不用于TCP服务器。
SO_REUSEADDR允许完全相同的地址和端口的重复绑定。但这只用于UDP的多播,不用于TCP。SO_REUSEADDR允许完全重复的捆绑:当一个IP地址和端口绑定到某个套接口上时,还允许此IP地址和端口捆绑到另一个套接口上。一般来说,这个特性仅在支持多播的系统上才有,而且只对UDP套接口而言(TCP不支持多播)。
SO_REUSEPORT选项有如下语义: 此选项允许完全重复捆绑,但仅在想捆绑相同IP地址和端口的套接口都指定了此套接口选项才行。
如果被捆绑的IP地址是一个多播地址,则SO_REUSEADDR和SO_REUSEPORT等效。
使用这两个套接口选项的建议: 在所有TCP服务器中,在调用bind之前设置SO_REUSEADDR套接口选项; 当编写一个同一时刻在同一主机上可运行多次的多播应用程序时,设置SO_REUSEADDR选项,并将本组的多播地址作为本地IP地址捆绑。
设置方法如下:
if(setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(constvoid*)&nOptval,sizeof(int))<0)...
附
Q:编写 TCP/SOCK_STREAM 服务程序时,SO_REUSEADDR到底什么意思?
A:这个套接字选项通知内核,如果端口忙,但TCP状态位于 TIME_WAIT ,可以重用端口。如果端口忙,而TCP状态位于其他状态,重用端口时依旧得到一个错误信息,指明"地址已经使用中"。如果你的服务程序停止后想立即重启,而新套接字依旧使用同一端口,此时SO_REUSEADDR 选项非常有用。必须意识到,此时任何非期望数据到达,都可能导致服务程序反应混乱,不过这只是一种可能,事实上很不可能。
一个套接字由相关五元组构成,协议、本地地址、本地端口、远程地址、远程端口。SO_REUSEADDR 仅仅表示可以重用本地本地地址、本地端口,整个相关五元组还是唯一确定的。所以,重启后的服务程序有可能收到非期望数据。必须慎重使用 SO_REUSEADDR 选项。
举例
例子1:测试上面第一种情况。
#include<netinet/in.h>#include<sys/socket.h>#include<time.h>#include<stdio.h>#include<string.h>#defineMAXLINE100intmain(intargc,char**argv){intlistenfd,connfd;structsockaddr_inservaddr;charbuff[MAXLINE+1];time_tticks;unsignedshortport;intflag=1,len=sizeof(int);port=10013;if((listenfd=socket(AF_INET,SOCK_STREAM,0))==-1){perror("socket");exit(1);}bzero(&servaddr,sizeof(servaddr));servaddr.sin_family=AF_INET;servaddr.sin_addr.s_addr=htonl(INADDR_ANY);servaddr.sin_port=htons(port);if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&flag,len)==-1){perror("setsockopt");exit(1);}if(bind(listenfd,(structsockaddr*)&servaddr,sizeof(servaddr))==-1){perror("bind");exit(1);}elseprintf("bindcallOK!\n");if(listen(listenfd,5)==-1){perror("listen");exit(1);}for(;;){if((connfd=accept(listenfd,(structsockaddr*)NULL,NULL))==-1){perror("accept");exit(1);}if(fork()==0)/*childprocess*/{close(listenfd);/*关闭监听套接字,子进程不需要。*/ticks=time(NULL);snprintf(buff,100,"%.24s\r\n",ctime(&ticks));write(connfd,buff,strlen(buff));close(connfd);sleep(1);execlp("run",NULL);perror("execlp");exit(1);}close(connfd);exit(0);/*endparent*/}}
gcc123.c-orunsudocprun/sbinsudochmod777/sbin/run
测试:编译为run程序,放到一个自己PATH环境变量里的某个路径里,例如$HOME/bin,运行run,然后telnet localhost 10013看结果。
第一步 运行程序,此时程序阻塞在accept()这个位置。
第二步 重新打开一个终端,执行以下命令。
第三步: 可以看到次异步运行的程序退出,并打印了bind call OK! 说明子进程被执行,并且成功绑定了端口10013,验证了第一种情况。
第二种情况我没有环境测,所以就不给测试程序了,大家有条件的可以自己写一个来测试一下。测试第三种情况的程序 读取本地ip地址ifconfig
可以得到本地地址为:
eth0:192.168.43.171lo:127.0.0.1
测试代码
#include<netinet/in.h>#include<sys/socket.h>#include<time.h>#include<stdio.h>#include<string.h>#defineMAXLINE100intmain(intargc,char**argv){intfd1,fd2;structsockaddr_inservaddr1,servaddr2;charbuff[MAXLINE+1];time_tticks;unsignedshortport;intflag=1,len=sizeof(int);port=10013;if((fd1=socket(AF_INET,SOCK_STREAM,0))==-1){perror("socket");exit(1);}if((fd2=socket(AF_INET,SOCK_STREAM,0))==-1){perror("socket");exit(1);}bzero(&servaddr1,sizeof(servaddr1));bzero(&servaddr2,sizeof(servaddr2));servaddr1.sin_family=AF_INET;servaddr2.sin_family=AF_INET;if(inet_pton(AF_INET,"127.0.0.1",&servaddr1.sin_addr)<=0){printf("inet_pton()callerror:127.0.0.1\n");exit(1);}if(inet_pton(AF_INET,"192.168.43.171",&servaddr2.sin_addr)<=0){printf("inet_pton()callerror:128.160.1.230\n");exit(1);}servaddr1.sin_port=htons(port);servaddr2.sin_port=htons(port);if(setsockopt(fd1,SOL_SOCKET,SO_REUSEADDR,&flag,len)==-1){perror("setsockopt");exit(1);}if(setsockopt(fd2,SOL_SOCKET,SO_REUSEADDR,&flag,len)==-1){perror("setsockopt");exit(1);}if(bind(fd1,(structsockaddr*)&servaddr1,sizeof(servaddr1))==-1){perror("bindfd1");exit(1);}if(bind(fd2,(structsockaddr*)&servaddr2,sizeof(servaddr2))==-1){perror("bindfd2");exit(1);}printf("bindfd1andfd2OK!\n");/*putotherprocesshere*/getchar();exit(0);/*end*/}
执行结果
结果
由于第四种情况只用于UDP的多播,和TCP的使用没多大关系,所以就不写测试例子了。自己有兴趣的可以写。更多Linux 嵌入式 知识,请关注 一口Linux
- 上一篇:dns的端口号是
- 下一篇:如何查看服务器端口号