网络编程之Elementary TCP Sockets(二)

本文介绍了Unix环境下网络编程的基础知识,包括使用fork实现并发服务器的方法、获取socket名称的getsockname和getpeername函数,以及如何通过fork和exec实现并发服务器的具体步骤。

1. fork and exec Functions

笔者在APUE中比较详细的记录过fork函数,这里相关细节不在赘述,只看看和网络编程相关的概念:

  • The parent calls accept and then calls fork. The connected socket is then shared between the parent and child. Normally, the child then reads and writes the connected socket and the parent closes the connected socket.
  • A process makes a copy of itself so that one copy can handle one operation
    while the other copy does another task. This is typical for network servers.

2. getsockname and getpeername Functions

#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen);
int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen);
Both return: 0 if OK,1 on error

具体这两个函数的作用,简单来说就是为了找到由系统决定bind函数中绑定的地址和端口:

  • After connect successfully returns in a TCP client that does not call bind, getsockname returns the local IP address and local port number assigned to the connection by the kernel.
  • After calling bind with a port number of 0 (telling the kernel to choose the local
    port number), getsockname returns the local port number that was assigned.
  • getsockname can be called to obtain the address family of a socket
  • In a TCP server that binds the wildcard IP address, once a connection is established with a client (accept returns successfully), the server can call getsockname to obtain the local IP address assigned to the connection. The socket descriptor argument in this call must be that of the connected socket, and not the listening socket.
  • When a server is execed by the process that calls accept, the only way the server can obtain the identity of the client is to call getpeername. This is what happens whenever inetd forks and execs a TCP server. inetd calls accept (top left box) and two values are returned: the connected socket descriptor, connfd, is the return value of the function, and the small box we label ‘‘peer ’s address’’ (an Internet socket address structure) contains the IP address and port number of the client. fork is called and a child of inetd is created. Since the child starts with a copy of the parent’s memory image, the socket address structure is available to the child, as is the connected socket descriptor (since the descriptors are shared between the parent and child). But when the child execs the real server (say the Telnet server that we show), the memory image of the child is replaced with the new program file for the Telnet server (i.e., the socket address structure containing the peer’s address is lost), and the connected socket descriptor remains open across the exec. One of the first function calls performed by the Telnet server is getpeername to obtain the IP address and port number of the client.

第三点配上下图就比较清楚,也就是fork-exec会用新的程序替代老程序从而丢失了原本accept返回的地址信息,但是因为文件描述符依然被新进程继承,所以可以通过getpeername找回client的相关地址信息。
这里写图片描述

3. Concurrent Servers

一句话概括:The simplest way to write a concurrent server under Unix is to fork a child process to handle each client.其代码模板如下:

pid_t pid;
int listenfd, connfd;
listenfd = Socket( ... );
/* fill in sockaddr_in{} with server’s well-known port */
Bind(listenfd, ... );
Listen(listenfd, LISTENQ);
for ( ; ; ) {
		connfd = Accept(listenfd, ... ); /* probably blocks */
		if ( (pid = Fork()) == 0) {
		Close(listenfd); /* child closes listening socket */
		doit(connfd); /* process the request */
		Close(connfd); /* done with this client */
		exit(0); /* child terminates */
}
Close(connfd); /* parent closes connected socket */
}

其实上面程序最好玩的地方就是close在父进程调用,这点也是上一篇强调的地方,因为一个socketfd,经过fork以后其引用数就变为2,父进程必须调用close关闭它,否则会造成socketfd在子进程调用close无法真正关闭的现象。以上程序执行的过程,看下图会有比较直观的感受:

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

下载前可以先看下教程 https://pan.quark.cn/s/a4b39357ea24 Job-Recommend 蚂蚁集团招聘内推(校招、社招) 校招 蚂蚁集团 2023届实习生招聘开始啦~ 蚂蚁集团是中国最大的移动支付平台【支付宝】的母公司,也是全球领先的金融科技开放平台,致力于以科技推动包括金融服务业在内的全球现代服务业的数字化升级。 我们团队归属于支付宝事业群商家开放技术部,整个大团队致力于打造蚂蚁级的开放、产品、商户等通用业务平台,实现全局业务能力与商家资源的开放共享,对内助力于商家、用户、机构等服务体系构建,对外以小程序、生活号等为抓手激活支付+X的金融生活开放生态。 我们团队是城市化策略技术部,依托于亿级的商家及用户数据,通过数据、算法、工程构建城市智能决策网络及策略体系。 我们有耐心逗比的师兄,有温柔细致的师姐,有丰富多彩的团队活动,也有各式各样的员工关怀,快来联系我们吧! ! ! 招聘对象: 11-2023.10毕业的应届毕业生 招聘流程: 简历投递->在线笔试及测评->面试->发放实习offer->实习入职 岗位类型: 【Java研发岗位】 岗位要求: 本科及以上学历,计算机、通信、数据科学与大数据技术等相关专业。 熟练掌握java技术,对多线程、数据结构等有清晰的认识。 掌握常用数据结构、算法、设计模式,熟悉MySQL/Oracle数据库等关系型数据库。 具备较强的编程能力、数据分析能力、问题排查能力,工作主动,学习能力强。 【数据工程/数据挖掘岗位】 岗位要求: 1、对分布式计算有较深的认识, 熟练使用spark,hadoop等处理海量用户行为数据。 2、熟练运用python、shell等脚本编程语言。 3、熟练掌握概率论与数理统计者优先。 4...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值