国内最全IT社区平台 联系我们 | 收藏本站
华晨云阿里云优惠2
您当前位置:首页 > php开源 > php教程 > 服务器如何给多个客户端分配端口号

服务器如何给多个客户端分配端口号

来源:程序员人生   发布时间:2014-12-15 09:13:13 阅读次数:5942次

在1台计算机上,使用socket通讯时,不同进程辨别网络通讯的连接依托3个参数:通讯所用协议、地址IP、端口号。

服务器端来讲,通过bind、listen,以后accept建立新的连接,accept返回新连接的句柄,这样就建立了1条连接。那末新建立的连接使用的端口号是不是和listen所用端口号相同呢?之前我1直以为服务器会随机分配1个新的端口号来使用,后来发现错了。

由于1、现在使用多路IO复用epoll等,配置好点的服务器可以支持数10万个并发连接,端口号为16位,最多才2^16⑴,且加上1些经常使用的端口号不能使用,可用的端口号都没那末多。2、现在服务器大多使用防火墙,防火墙只对特定端口开放。如果accept随机分配端口号,会不能通过防火墙。

TCP/IP协议中,IP协议是端到真个协议,它只是负责把把数据发送到端,交付给上层而已。运输层TCP、UDP加上了端口号,目的是辨别不同的利用。其中TCP还实现了流量控制、可靠传输等,而UDP只是应当是没有对IP层数据进行处理了。

在以往的知识中,我知道1个利用程序只能使用1个端口号,如果accept返回的句柄还是使用listen的端口号,那末怎样实现通讯呢?如果建立多个连接,利用程序怎样区收到的信息来自哪一个客户端呢?

现在才理解到accept返回的句柄建立的连接包括4部份:源IP、源端口号、目的IP、目的端口号。这样在1个利用程序中,就算和多个客户端建立连接,在收到数据后,利用程序通过目的IP和目的端口号也能辨别是哪1条连接。

通过1个echo服务器来验证1下,client和server都在同1台机器上:

服务器监听8000端口,在未建立连接时,可以看到在监听8000


在通过1个客户端建立连接后,可以看到建立了1条连接,服务器真个端口号是8000,监听的还是8000。


在连接1个客户端,可以看到建立了两条连接,服务器端都是使用8000,监听的还是8000。


下面是server端代码:

#include<stdio.h> #include<sys/socket.h> #include<unistd.h> #include<errno.h> #include<netinet/in.h> void str_echo(int sockfd) { int n; char buf[1024]; again: while((n=read(sockfd,buf,1024))>0) { write(sockfd,buf,n); } if(n<0&&errno==EINTR) goto again; else if(n<0) printf("str_error:read error"); } int main(int argc, char **argv) { int listenfd, connfd; pid_t childid; socklen_t clilen; struct sockaddr_in cliaddr, servaddr; listenfd=socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=htonl(INADDR_ANY);//host IP servaddr.sin_port=htons(8000);//port bind(listenfd,(struct sockaddr*)&servaddr,sizeof(struct sockaddr)); listen(listenfd,5);//最多处理5个监听 for(;;) { clilen=sizeof(cliaddr); //进场阻塞在accept上 connfd=accept(listenfd, (struct sockaddr*)&cliaddr,&clilen); if(childid=fork()==0)//child { close(listenfd);//在子进程中关闭监听 str_echo(connfd);//处理监听的连接 exit(0); } } close(listenfd); }

客户端代码:

#include<stdio.h> #include<sys/socket.h> #include<netinet/in.h> #include<unistd.h> void str_cli(FILE *fp, int sockfd) { char sendline[1024],recvline[1024]; while(fgets(sendline, 1024, fp)!=NULL) { //发给Server write(sockfd,sendline,sizeof(sendline)); //读Server if(read(sockfd,recvline,1024)==0) { printf("str_cli:server terminated prematurely "); exit(0); } //fputs(recvline,stdout); printf("%s",recvline); } } int main(int argc, char **argv) { int sockfd; struct sockaddr_in servaddr; if(argc!=2) { printf("usage:client IPaddress "); exit(0); } sockfd=socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_port=htons(8000); //把输入的IP存到sin_addr中 inet_pton(AF_INET,argv[1],&servaddr.sin_addr); printf("server IP:%s ",argv[1]); //建立连接 connect(sockfd,(struct sockaddr*)&servaddr,sizeof(struct sockaddr)); str_cli(stdin,sockfd); exit(0); }


生活不易,码农辛苦
如果您觉得本网站对您的学习有所帮助,可以手机扫描二维码进行捐赠
程序员人生
------分隔线----------------------------
分享到:
------分隔线----------------------------
关闭
程序员人生