TCP
面向连接的 可靠的 字节流服务
UDP
无连接 不可靠的 数据报服务
IP
无连接 不可靠的 无状态的
RUDP:介于TCP和UDP中间,两者取其中。
TCP编程流程:
服务器:socket bind listen accept recv/send close
客户端:socket connect send/recv close
TCP编码流程:
服务器:
实现TCP需要的头文件:
#include
#include
#include
#include
需要的函数原型:
① int socket(int domain, int type, int protocol);//创建socket
返回值:-1 出错,只要返回值>=0即正确
返回的值,也是文件描述符 socket文件描述符
domain:协议簇 一般用AF_INET(TCP/IP)协议簇
type:在该协议簇下选择的具体的协议 TCP:SOCK_STREAM UDP:SOCK_DGRAM
pro:具体的协议下更具体的协议:默认给0
② int bind(int sockfd, struct sockaddr *seraddr, socklen_t);
sockfd:socket返回的文件描述符
struct sockaddr *seraddr:服务器端的ip地址
socklen_t:第二个参数的长度
为了了解这个函数我们还需要知道:
如何标识一台主机?
需要知道IP地址+端口号
struct sockaddr_in
{
sa_family_t sin_family;//地址族
u_int16_t sin_port;//端口号
struct in_addr sin_addr;IP地址
}
struct in_addr
{
u_int32_t s_addr;//无符号32位整型值
}
端口号的转化函数:将IP地址转化成整型值
端口号取值范围:0-65535 但0-1024(无法使用,系统预留) 1024-5000保留 一般我们用5000以上端口号
地址转化函数:
主机字节序:
大端模式:高位存低地址
小端模式:高位存高地址
网络字节序:都用的大端模式(如果主机是小端模式不经过转化在网络中传输数据就会乱套)
③ int listen(int sockfd, int size);//给sockfd启动监听
sockfd:socket返回的socket值监听sockfd套接字。监听:等客户端连接
size:指定已完成连接队列的大小。一般为:size + 1
两个队列:
已完成连接的队列
正在完成连接的队列
④ int accept(int sockfd, struct sockaddr* cliaddr, int len);
sockfd:接收连接的套接字
struct coskaddr cliaddr:客户端连接时内核自动填充
int *len:填充的大小
返回值:返回维护本次连接的文件描述符,服务器和客户端通讯时通过accept返回的文件描述符进行通讯
⑤ int recv(int c, void *buff ,int buffsize, int flag);//获取数据
int c:标识从哪个客户端来获取数据
void *buff:读到的数据存放在哪
int buffsize:buff缓冲区的大小有多少,一次最多读多少个字节的数据
int flag:不用默认给0
⑥int send(int c, void *buff,int datasize, int flag); 发送数据
int c:将数据发送给谁
void *buff:发送的数据从哪开始
int datasize:数据的大小
int flag:不用默认给0
服务器端编码流程:
1.调用socket()创建套接字;
2.定义strcuct sockaddr_in ser,cli;
3.对地址族,端口号,IP地址进行赋值;
4.bind()进行命名;
5.listen进行启动监听
6.while(1)循环
{
int c = accept();获取连接
while(1)//一个客户端与服务器进行多次通讯
{recv()/send();}//收发
}//一个服务器可以多次处理不同客户端的连接
7.close();
客户端:
需要的函数原型:
① int socket(int domain, int type, int protocol);//与前面一样
② int connect(int sockfd, (struct sockaddr*)seraddr, int len);//发起连接
int sockfd:上面socket返回的文件描述符
(struct sockaddr*)seraddr:和哪个服务器进行连接,服务器的地址和端口号
int len:连接的长度
返回:-1 连接失败 返回>-1 成功
③ int send(int c, void *buff,int datasize, int flag);//发起连接
④ int recv(int c, void *buff ,int buffsize, int flag);//获取数据
⑤ close();//发送数据
客户端编码流程:
1.socker();创建套接字
2.connect();发起连接和服务器进行连接
3.while(1)//多次接受发送数据
{
send()/recv();多次
}
4.close();
下图为TCP客户端的创建:
TCP服务器与客户端连接测试如图:
一个客户端与服务器的连接(连接成功):
多个客户端与服务器的连接(连接失败):
UDP编程流程:
服务器:socket bind recvfrom/sendto close
客户端:socket sendto/recvfrom close
UDP编码流程:
服务器:
需要的函数原型:
① int socket(int domain, int type, int protocol);//创建socket
int type:需要UDP :SOCK_DGRAM协议
② int bind(int sockfd,struct sockaddr* seraddr,int size);//UDP是无连接,不可靠数据报服务,所以不需要监听,无linsten;也不需要accpet
③ int recvfrom(int sockfd, void *buff, int size, int flag, struct sockaddr *cliaddr, int *addrlen);//接收客户端的数据+客户端地址信息
int sockfd:从哪获取数据
void *buff:将数据放在哪
int size:buff缓冲区的大小有多少,一次最多读多少个字节的数据
int flag:默认0
struct sockaddr *cliadd, int *addrlen:保留客户端的IP地址与端口号
④ int sendto(int sockfd,void * buff, int datalen, int flag, struct sockaddr *cliaddr, int addrlen);//发送数据(指定数据发送给哪个客户端)
int sockfd,void * buff, int datalen, int flag:发送的数据
struct sockaddr *cliaddr, int addrlen:发送给谁
⑤ int close(int sockfd);//关闭
如下图为服务器的创建:
客户端:
需要的函数原型:
① int socket(int domain, int type, int protocol);//创建socket
int type:需要UDP :SOCK_DGRAM协议
② int recvfrom(int sockfd, void *buff, int size, int flag, struct sockaddr *cliaddr, int *addrlen);//接收客户端的数据+客户端地址信息
③ int sendto(int sockfd,void * buff, int datalen, int flag, struct sockaddr *cliaddr, int addrlen);//发送数据(指定数据发送给哪个客户端)
④ int close(int sockfd);//关闭
如下图为客户端的创建:
UDP服务器与客户端连接测试如图:
一个客户端与服务器的连接(连接成功):
多个客户端与服务器的连接(连接成功):