php 在服务器开一个端口号,服务器如何给多个客户端分配端口号

在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

64d6e72fc136f6c7dceb4228aaa814ca.png

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

06925e986d0afaeb4183bb8727c7fbf6.png

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

682e00bc34106a695913511ebd863822.png

下面是server端代码:

#include

#include

#include

#include

#include

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

#include

#include

#include

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);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值