值得收藏的TCP套接口编程文章

首先启动服务器,等待客户端连接

启动客户端,连接到服务器

客户端发送一个请求给服务器,服务器处理请求,响应客户端

循环步骤3

客户端给服务器发一个文件结束符,关闭客户端连接

服务器也关闭连接

img

基本TCP客户-服务器程序的套接口函数

接口编程基本函数 socket 函数

为了执行网络I/O,一个进程(无论是服务端还是客户端)必须做的第一件事情就是调用socket函数。

#include <sys/socket.h> /* basic socket definitions */ int socket(int family, int type, int protocol);/* 返回:非负描述字——成功,-1——出错 */

family——协议族

族 解释
AF_INET   IPv4协议  
AF_INET6   IPv6协议  
AF_LOCAL   Unix域协议  
AF_ROUTE   路由套接口  
AF_KEY   密钥套接口  

type——套接口类型

类型 解释
SOCK_STREAM   字节流套接口  
SOCK_DGRAM   数据报套接口  
SOCK_RAW   原始套接口  

下面是有效的family和type组合(简略版):

AF_INET AF_INET6
SOCK_STREAM   TCP   TCP  
SOCK_DGRAM   UDP   UDP  
SOCK_RAW   IPv4   IPv6  

socket函数返回一个套接口描述字,简称套接字(sockfd)。获取套接字无需指定地址,只需要指定协议族和套接口类型(如上表中的组合)。

connect函数

TCP客户用connect函数来建立一个与TCP服务器的连接。

#include <sys/socket.h> /* basic socket definitions */ int connect(int sockfd, const struct sockaddr * servaddr, socklen_t addrlen);/* 返回:0——成功,-1——出错 */

参数sockfd便是socket函数返回的套接口描述字。

套接口地址结构servaddr必须包含服务器的IP地址和端口号。

客户端不必非要绑定一个端口(调用bind函数),内核会选择源IP和一个临时端口。

connect函数会触发TCP三次握手。有可能出现下面的错误情况:

1.客户端未收到SYN分节的响应

第一次发出未收到,间隔6s再发一次,再没收到,隔24秒再发一次,总共等待75s还没收到则返回错误( ETIMEDOUT)。可以用时间日期程序验证一下:

查看本地网络信息:

JACKIELUO-MC0:intro jackieluo$ ifconfig en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500 ether f4:0f:24:2a:72:a6 inet6 fe80::1830:dbd:1b29:2989%en0 prefixlen 64 secured scopeid 0x6 inet 192.168.0.101 netmask 0xffffff00 broadcast 192.168.0.255 nd6 options=201<PERFORMNUD,DAD> media: autoselect status: active

将程序指向本地地址192.168.0.101(确保时间日期服务器程序已运行),成功:

JACKIELUO-MC0:intro jackieluo$ ./daytimetcpcli 192.168.0.101 Sat Oct 6 17:06:55 2018

将程序指向本地子网地址192.168.0.102,其主机ID(102)不存在,等待几分钟后超时返回:

JACKIELUO-MC0:intro jackieluo$ ./daytimetcpcli 192.168.0.102 connect error: Operation timed out

2.收到RST

即服务器主机在指定端口上没有等待连接的进程,这称为“hard error”,客户端一接收到RST,马上返回错误(ECONNREFUSED)。验证:

关闭之前本机运行的daytimetcpsrv进程

将程序指向本地地址192.168.0.101:

JACKIELUO-MC0:intro jackieluo$ ./daytimetcpcli 192.168.0.101 connect error: Connection refused

3.发出的SYN在路由器上引发了目的不可达ICMP错误

这个错误被称为“soft error”,最终返回EHOSTUNREACH或者ENETUNREACH。

bind函数

函数bind为套接口分配一个本地协议地址,包括IP地址和端口号。

#include <sys/socket.h> /* basic socket definitions */ int bind(int sockfd, const struct sockaddr * servaddr, socklen_t addrlen);/* 返回:0——成功,-1——出错 */

客户端可以不调用这个函数,由内核选择一个本地ip的临时端口就好。

服务器一般都会调用bind函数绑定ip地址和端口,供客户端调用。一个例外是RPC(远程过程调用)服务器,它由内核为其选择临时端口。然后通过RPC端口映射器进行注册,客户端与该服务器连接之前,先通过端口映射器获取服务器的端口。

进程可以把一个特定的IP地址捆绑到它的套接口上。对于客户端,它发送的请求,源IP地址就是这个地址;对于服务器,如果绑定了IP地址,则只接受目的地为此IP地址的客户连接。

如果服务器不把IP地址绑定到套接口上,那么内核把客户端发送SYN所在分组的目的IP地址作为服务器的源IP地址。(即服务器收到SYN的IP)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpdjzs.html