sockets: TCP

###########################################################

TCP套接字编程相关的系统调用(内核中的传输层):

###########################################################

 

大多数TCP服务器是并发的,需要用到fork和exec。

 

父进程关闭已连接套接字描述符connfd,父进程可以接着处理其它客户的连接请求。

子进程关闭监听套接字描述符listenfd,子进程通过connfd和客户进行通信,完成后用close或exit来关闭子进程的connnfd。

 

已连接套接字描述符每个客户和服务器连接后都有一个,监听套接字描述符一个服务器一般只有一个。

 

客户端用socket函数来获取一个未命名套接字描述符:

服务端用socket函数来获取一个监听套接字描述符:

int listenfd = int socket(int family, int type, intprotocol);

socket的参数都是和协议相关的。

 

family:(网络层协议)

分两种,一般用地址族。

bsd和linux:(AF:地址族)

AF_INET(ipv4域)

AF_INET6(ipv6域)

AF_LOCAL(unix域)=AF_UNIX

AF_ROUTE(路由域)

AF_KEY(秘钥域)

AF_PACKET

 

svr4:(PF:协议族)

PF_INET

PF_INET6

PF_UNIX

PF_NCA

 

type:

SOCK_STREAM(字节流套接字)(tcp、sctp)

SOCK_DGRAM(数据报套接字)(udp)

SOCK_SEQPACKET(有序分组套接字)(sctp)

SOCK_RAW(原始套接字)(ipv4、ipv6)

SOCK_RDM(无序可靠数据报套接字)

 

protocol:(传输层协议)

0:tcp和udp,一般用这个,表示默认值

IPPROTO_SCTP: sctp用这个。

 

客户用connect建立客户端未命名套接字和服务监听套接字的连接:

考虑超时问题

int connect(int sockfd, const struct sockaddr *servaddr, socklen_taddrlen);

sockfd:socket()返回的套接字描述符

struct sockaddr:通用套接字地址结构

addrlen:结构的长度

后两个参数就是服务器的通用套接字地址结构和长度,必须填写。

 

调用bind函数把一个地址和端口赋予一个套接字(给套接字命名):

在建立连接之前如果没有调用bind,内核会选择一个IP和端口号给套接字。

int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrltn);

sockfd:socket()返回的套接字描述符

struct sockaddr:ipv4通用套接字地址结构

addrlen:结构的长度,sizeof(struct sockaddr)

如果为通配地址且为INADDR_ANY=0,表示bind时由内核选择IP;

如果用指定的本地IP,就用指定的IP。

如果端口号为0,表示bind时由内核选择端口号;

如果端口号不为0,就用指定的端口。

 

TCP服务调用listen函数来创建队列保存未处理的请求:

int listen(int sockfd, int backlog);

backlog:规定内核应该为相应套接字排队的最大连接个数。

 

连接队列:

未完成队列:三路握手未完成

已完成队列:三路握手完成

 

TCP服务调用accept函数用来接受连接;

并返回一个新的专用的套接字描述符:

考虑超时问题

int connfd = int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);

成功返回:已连接套接字描述符

sockfd:监听套接字描述符

cliaddr:返回客户的协议地址

addrlen:返回客户的协议地址的大小, sizeof(struct sockaddr)

后两个参数就是服务器返回的客户端的通用套接字地址结构和长度,不需要可以忽略。

 

发送数据:

write(一般用这个)

send

sendmsg

sendto(不能指定IP和端口号)

 

接收数据:

read(一般用这个)

recv

recvmsg

recvfrom(不返回IP和端口号)

 

关闭套接字描述符:

int close(int sockfd);

close有两个限制:

1.     close把描述符的引用计数减1,仅在计数变为0才关闭套接字。

2.     close终止读和写两个方向的数据传送。

 

关闭套接字描述符:

int shutdown(int sockfd, int how);

how:

SHUT_RD=0:关闭读这一半,套接字中不再有数据可接收,套接字接收缓冲区中的数据也清空。

SHUT_WR=1:关闭写这一半,在套接字发送缓冲区中的数据会被发送出去,然后正常终止连接。

SHUT_RDWR=2:关闭读和写

 

返回与某个套接字关联的本地协议地址:

int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t*addrlen);

返回sockfd的通用套接字地址结构和长度。

 

返回与某个套接字关联的对端协议地址:

int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen);

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值