Linux22 TCP编程流程

TCP:面向连接的、可靠的、字节流服务
UDP:无连接、不可靠的、数据报服务
IP:无连接、不可靠的、无状态的
无状态:数据的发送、传输、接收相互独立的,没有上下文关系。接收端接收的数据有可能重复和乱序。
头文件

# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <assert.h>
# include <netinet/in.h>
# include <arpa/inet.h>
#include<sys/types.h>
#include<sys/socket.h>

TCP服务器编程流程

1、创建socket
int socket(int domain, int type, int protocol);
domain: 协议域或者地址簇,每种协议都有其特定的应用场景,这里,我们可以通俗的将domain理解成协议种类,egAF_INET。
type:具体协议,面向连接的流式传输模式TCP:SOCK_STREAM、无连接的数据报传输方式UDP:SOCK_UGRAM。
protocol: 默认给0.原因:IPv4协议族里,面向连接的流式套接字一般指的都是TCP协议。一般情况下,对于某种具体的套接字类型(流式或数据报式)都只有一种对应的实现协议,但某些协议族有可能有多种协议。对于IPv4而言,在创建socket套接字时,当指定了地址簇、套接字类型、protocol协议字段一般都设置为0。
2、绑定地址
int bind(int sockfd, struct sockaddr saddr,int len);
sockfd:socket()返回的文件描述符
saddr:的类型的定义如下:
struct sockaddr
{
unisgned short as_family;
char sa_data[14];
};
我们在Internet编程中一般不用这个结构,而是用:
struct sockaddr_in
{
unsigned short sin_family;//协议族
unsigned short int sin_port;//端口号0-1024普通用户无法使用5000以上
struct in_addr sin_addr;//IP,点分十进制,转成整型
}
在调用bind()函数时将一个sockaddr_in{}类型的对象强制转换成sockaddr{}类型赋给bind()函数的第二个参数。
len:addrlen指的是第二个参数在sockaddr{}类型下的实际长度。
它的主要作用是将由socket()函数创建socket文件描述符和一个本地地址结构体绑定起来。本地地址结构体一般都指明了我们这个socket文件描述符所属的协议簇,如果本地是多网卡多IP地址的话,可以在指定与哪个地址进行绑定,如果是任意IP地址一般将地址字段设置为htonl(INADDR_ANY),以及所使用的端口。
3、系统监听:
int listen(int sockfd, int backlog);
sockfd:socket()返回的文件描述符
backlog:一般为5,已完成连接的队列大小backlog+1,测出来的,给5维护6个
监听客户端连接,只是启动监听
4、接受连接
int accept(int sockfd, struct sockaddr
caddr, int* len);
sockfd:socket()返回的文件描述符
caddr:中存储了来自客户端的一些地址信息。//内核自动填充
len:指明了第二个参数所占的字节数。
返回值:返回维护本次连接的文件描述符。
当客户端用connect()去连接服务器时,针对于TCP这样的流式套接字,此时便后触发其3次握手的流程。当然3次握手成功的速度依赖于网络的处理性能。当服务器端收到客户端发来的第一个SYN报文,该连接就为半连接状态,处于半连接队列中;对于那些完成了3次握手的连接,TCP会将其从半连接队列移到一个名为established状态的已连接队列里,在accept()函数返回之前该连接项暂时是不可用的。
该函数会从处于established状态的连接队列头部取出一个连接,然后生成一个新的socket连接,并返回新的socket文件描述。
5、接收数据:recv、recvfrom、recvmsg
int recv(int c,void* buff,int buffsize,int flag);//只用在面向连接的套接字。
c;accept()返回的文件描述符
buff:接收缓冲区
buffsize:接收缓冲区大小
flag:一般为0
返回值:返回接收数据个数,返回值小于0,出错,客户端关闭返回值等于0
对于recvfrom 和 recvmsg,可同时应用于面向连接的和无连接的套接字。只要将recvfrom的第五个参数设置NULL,几乎等同于recvmsg。如果消息太大,无法完整存放在所提供的缓冲区时会根据不同的套接字,多余的字节会丢弃。假如套接字上没有消息可以读取,除非套接字已被设置为非阻塞模式,否则接收调用会等待消息的到来。
6、发送数据:send、sendto、sendmsg
int send(int c,void* buff,int datasize,int flag);//send只用于面向连接的套接字。
c;accept()返回的文件描述符
buff:发送缓冲区
datasize:发送数据大小
flag:一般为0
sendto 和 sendmsg既可用于无连接的套接字,也可用于基于连接的套接字。除非套接字设置为非阻塞模式,否则调用将会阻塞直到数据被发送完。
7、关闭连接
int close(int fd);

TCP客户端编程流程

1、创建socket
int socket(int domain, int type, int protocol);
domain: 协议域或者地址簇,每种协议都有其特定的应用场景,这里,我们可以通俗的将domain理解成协议种类,egAF_INET。
type:具体协议,面向连接的流式传输模式TCP:SOCK_STREAM、无连接的数据报传输方式UDP:SOCK_UGRAM。
protocol: 默认给0.原因:IPv4协议族里,面向连接的流式套接字一般指的都是TCP协议。一般情况下,对于某种具体的套接字类型(流式或数据报式)都只有一种对应的实现协议,但某些协议族有可能有多种协议。对于IPv4而言,在创建socket套接字时,当指定了地址簇、套接字类型、protocol协议字段一般都设置为0。
2、主动连接
int connect(int sockfd, struct sockaddr saddr, int addrlen);
sockfd:socket()返回的文件描述符
caddr:中存储了来自服务器的一些地址信息。//内核自动填充
len:指明了第二个参数所占的字节数。
返回值:-1为出错
该函数是客户端主动连接服务器的API调用。流式套接字可以调用,面向无连接的套接字也可以使用。但在实际应用中,后者调用该函数的情形还是比较少。
对于面向连接的套接字,当调用该函数时,客户端会向服务端发起一个SYN的连接请求,对于TCP来说此时就开始了3次握手的流程。如果客户端设置为阻塞模式,那么connect()函数会一直阻塞,直到3次握手成功或超时失败才返回。
3、接收数据:recv、recvfrom、recvmsg
int recv(int c,void
buff,int buffsize,int flag);//只用在面向连接的套接字。
c;accept()返回的文件描述符
buff:接收缓冲区
buffsize:接收缓冲区大小
flag:一般为0
返回值:返回接收数据个数,返回值小于0,出错,客户端关闭返回值等于0
对于recvfrom 和 recvmsg,可同时应用于面向连接的和无连接的套接字。只要将recvfrom的第五个参数设置NULL,几乎等同于recvmsg。如果消息太大,无法完整存放在所提供的缓冲区时会根据不同的套接字,多余的字节会丢弃。假如套接字上没有消息可以读取,除非套接字已被设置为非阻塞模式,否则接收调用会等待消息的到来。
4、发送数据:send、sendto、sendmsg
int send(int c,void* buff,int datasize,int flag);//send只用于面向连接的套接字。
c;accept()返回的文件描述符
buff:发送缓冲区
datasize:发送数据大小
flag:一般为0
sendto 和 sendmsg既可用于无连接的套接字,也可用于基于连接的套接字。除非套接字设置为非阻塞模式,否则调用将会阻塞直到数据被发送完。
5、关闭连接
int close(int fd);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值