【Linux网络编程】TCP编程

00. 目录

01. TCP概述

传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。

TCP旨在适应支持多网络应用的分层协议层次结构。 连接到不同但互连的计算机通信网络的主计算机中的成对进程之间依靠TCP提供可靠的通信服务。TCP假设它可以从较低级别的协议获得简单的,可能不可靠的数据报服务。 原则上,TCP应该能够在从硬线连接到分组交换或电路交换网络的各种通信系统之上操作。

02. TCP特点

TCP是一种面向广域网的通信协议,目的是在跨越多个网络通信时,为两个通信端点之间提供一条具有下列特点的通信方式。

(1)基于流的方式;

(2)面向连接;

(3)可靠通信方式;

(4)在网络状况不佳的时候尽量降低系统由于重传带来的带宽开销;

(5)通信连接维护是面向通信的两个端点的,而不考虑中间网段和节点。

为满足TCP协议的这些特点,TCP协议做了如下的规定:

①数据分片:在发送端对用户数据进行分片,在接收端进行重组,由TCP确定分片的大小并控制分片和重组;

②到达确认:接收端接收到分片数据时,根据分片数据序号向发送端发送一个确认;

③超时重发:发送方在发送分片时启动超时定时器,如果在定时器超时之后没有收到相应的确认,重发分片;

④滑动窗口:TCP连接每一方的接收缓冲空间大小都固定,接收端只允许另一端发送接收端缓冲区所能接纳的数据,TCP在滑动窗口的基础上提供流量控制,防止较快主机致使较慢主机的缓冲区溢出;

⑤失序处理:作为IP数据报来传输的TCP分片到达时可能会失序,TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层;

⑥重复处理:作为IP数据报来传输的TCP分片会发生重复,TCP的接收端必须丢弃重复的数据;

⑦数据校验:TCP将保持它首部和数据的检验和,这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到分片的检验和有差错,TCP将丢弃这个分片,并不确认收到此报文段导致对端超时并重发。

在这里插入图片描述

03. TCP中CS架构

基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下:
在这里插入图片描述

04. TCP相关函数

4.1 socket函数

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
功能: 
	创建一个套接字
参数:
domain:
	AF_INET 这是大多数用来产生socket的协议,使用TCP或UDP来传输,用IPv4的地址
	AF_INET6 与上面类似,不过是来用IPv6的地址
	AF_UNIX 本地协议,使用在Unix和Linux系统上,一般都是当客户端和服务器在同一台及其上的时候使用
type:
	SOCK_STREAM 这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。
	SOCK_DGRAM 这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的连接。
	SOCK_SEQPACKET该协议是双线路的、可靠的连接,发送固定长度的数据包进行传输。必须把这个包完整的接受才能进行读取。
	SOCK_RAW socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)
	SOCK_RDM 这个类型是很少使用的,在大部分的操作系统上没有实现,它是提供给数据链路层使用,不保证数据包的顺序
	
protocol:0 表示使用默认协议。
返回值:
	成功:返回指向新创建的socket的文件描述符,失败:返回-1,设置errno

4.2 bind函数

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能:
	将套接字与地址绑定。
	
参数:
	sockfd:
		socket文件描述符
	addr:
		构造出IP地址加端口号
	addrlen:
		sizeof(sockaddr)长度
返回值:
	成功返回0,失败返回-1, 设置errno

4.3 listen函数

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
sockfd:
	socket文件描述符
backlog:
	排队建立3次握手队列和刚刚建立3次握手队列的链接数和

4.4 accept函数

#include <sys/types.h> 		/* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
sockdf:
	socket文件描述符
addr:
	传出参数,返回链接客户端地址信息,含IP地址和端口号
addrlen:
	传入传出参数(值-结果),传入sizeof(addr)大小,函数返回时返回真正接收到地址结构体的大小
返回值:
	成功返回一个新的socket文件描述符,用于和客户端通信,失败返回-1,设置errno

4.5 connect函数

#include <sys/types.h> 					/* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockdf:
	socket文件描述符
addr:
	传入参数,指定服务器端地址信息,含IP地址和端口号
addrlen:
	传入参数,传入sizeof(struct sockaddr)大小
返回值:
	成功返回0,失败返回-1,设置errno

4.6 recv函数

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能: 
	接收数据
参数:
	sockfd:  套接字描述符   socket的返回值或者accept返回值
	buf: 接收数据缓存
	len: buf的长度
	flags: 接收数据的标志, 一般默认为0
	
返回值:
	成功: 实际读到的数据的字节数, 如果对方已经关闭了 返回0表示读到结尾
	失败: -1

4.7 send函数

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能: 
	发送数据
参数:
	sockfd:  套接字描述符  socket的返回值或者accept返回值
	buf: 发送的数据
	len: 发送数据的长度
	flags: 发送数据的标志 一般默认0
返回值:
	成功: 非零值  实际上发送数据的字节数
	失败: -1

05. TCP服务端示例

server.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

#define SIZE 128

//TCP服务端
int main(void)
{
    int ret = -1;
    int sockfd = -1;
    int connfd = -1;

    char buf[SIZE];

    struct sockaddr_in addr;
    struct sockaddr_in from;
    socklen_t len = sizeof(from);

    //1. 创建套接字(socket)
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sockfd)
    {
        perror("socket");
        return 1;
    }
    printf("sockfd = %d\n", sockfd);

    //2. 绑定(bind)
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(10086);

    inet_pton(AF_INET, "192.168.72.128", &addr.sin_addr);

    //绑定
    ret = bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
    if (-1 == ret)
    {
        perror("bind");
        return 1;
    }


    //3. 设置监听(listen)
    ret = listen(sockfd, 10);
    if (-1 == ret)
    {
        perror("listen");
        return 1;
    }
    printf("服务器处于监听状态....\n");

    //4. 接受客户端连接(accept)
    //sockfd 接受客户端连接的套接字
    //connfd 与客户端进行数据交互的套接字
    connfd = accept(sockfd, (struct sockaddr*)&from, &len);
    if (-1 == connfd)
    {
        perror("accept");
        return 1;
    }
    printf("客户端连接OK....\n");

    //5. 进行数据交互(read/write)
    while(1) 
    {
        memset(buf, 0, SIZE);
        ret = read(connfd, buf, SIZE); 
        if (ret <= 0)
        {
            break;
        }
        printf("buf: %s\n", buf);
    }

    //6. 断开连接(close)
    close(connfd);
    close(sockfd);

    return 0;
}

06. TCP客户端示例

client.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

#define SIZE 128


//TCP 客户端
int main(void)
{
    int i = 0;
    int ret = -1;
    int sockfd = -1;

    char buf[SIZE];

    struct sockaddr_in addr;

    //1. 创建套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);    
    if (-1 == sockfd)
    {
        perror("socket");
        return 1;
    }

    //2. 连接到服务端
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(10086);

    inet_pton(AF_INET, "192.168.72.128", &addr.sin_addr);
    ret = connect(sockfd, (struct sockaddr*)&addr, sizeof(addr));
    if (-1 == ret)
    {
        perror("connnect");
        return 1;
    }
    printf("连接到服务端Ok...\n");


    //3. 数据交互(read/write)
    for (i = 0; i < 5; i++)
    {
        memset(buf, 0, SIZE);
        sprintf(buf, "hello server %d", i);
        ret = write(sockfd, buf, strlen(buf));
        if (ret <= 0)
        {
            break;
        }
        printf("send ret = %d\n", ret);
        sleep(1);
    }

    //4. 断开连接
    close(sockfd); 
    
    return 0;
}

07. 附录

7.1 【Linux】一步一步学Linux网络编程教程汇总

7.2 百度百科 TCP 传输控制协议

猜你喜欢

转载自blog.csdn.net/dengjin20104042056/article/details/107636358