C语言 网络编程(十)TCP通信创建流程---客户端

简介: 在TCP通信中,客户端需通过一系列步骤与服务器建立连接并进行数据传输。首先使用 `socket()` 函数创建一个流式套接字,然后通过 `connect()` 函数连接服务器。连接成功后,可以使用 `send()` 和 `recv()` 函数进行数据发送和接收。最后展示了一个完整的客户端示例代码,实现了与服务器的通信过程。

TCP通信创建流程

1. 客户端创建TCP连接

在整个流程中, 主要涉及以下⼏个接⼝
            socket() : 创建套接字, 使⽤的套接字类型为流式套接字
            connect() : 连接服务器
            send() : 数据发送
            recv() : 数据接收

创建套接字

首先,我们需要创建套接字,套接字是通信的基础。我们可以通过 socket() 函数来创建套接字。

int socket(int domain, int type, int protocol);
参数:
    @domain
            地址族
            AF_UNIX, AF_LOCAL  本地通信,数据不仅过网卡
            AF_INET         IPV4 ineter⽹通信  
            AF_INET6        IPV6 ineter⽹通信
            AF_PACKET       网卡上的数据包通信
            ....


    @ type
            使⽤协议类型
                SOCK_STREAM 流式套接字(TCP)
                SOCK_DGRAM 报⽂套接字(UDP)
                SOCK_RAW原始套接字: (IP,ICMP)
                ......

    @protocol
            协议编号
            0 : 让系统⾃动识别
            IPPROTO_TCP : TCP协议
            IPPROTO_UDP : UDP协议


返回值:
        成功返回得到的⽂件描述符。当前可使用的最小描述符
        失败返回 -1

连接服务器

创建套接字之后,我们需要连接服务器。连接服务器需要调用 connect() 函数。

发起对套接字的连接 (基于⾯向连接的协议)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数:
    @sockfd
            套接字描述符

    @addr   连接的套接字的地址结构对象的地址 (⼀般为服务器)
            服务器地址
                struct sockaddr {
   
                    unsigned short sa_family; // 地址族 对应socket()中的domain
                    char sa_data[14]; // 地址数据 ip地址端口信息
                };

                struct sockaddr_in {
    
                    short int sin_family; // 地址族 AF_INET
                    unsigned short int sin_port; // 端口号
                    struct in_addr sin_addr;// IP地址
                    unsigned char sin_zero[8]; // 填充字节 为了对齐sockaddr
                };

                struct in_addr {
   
                    uint32_t       s_addr; // IP地址
                };

    @addrlen
            地址长度


返回值:
        成功返回0
        失败返回-1 并设置 errno

数据发送

连接服务器之后,我们就可以向服务器发送数据。发送数据需要调用 send() 函数。

基于套接字(建⽴连接)发送数据
int send(int sockfd, const void *buf, size_t len, int flags);
参数:
    @sockfd
            套接字描述符

    @buf    发送的数据

    @len    发送数据的长度

    @flags  发送标志
函数返回值:
    成功返回发送的字节数
    失败返回-1,并设置errno

数据接收

服务器向客户端发送数据之后,客户端就可以接收数据。接收数据需要调用 recv() 函数。

接收套接字的数据 (基于⾯向连接的协议)
int recv(int sockfd, void *buf, size_t len, int flags);
参数:
    @sockfd
            套接字描述符

    @buf    接收的数据

    @len    接收数据的长度

    @flags  接收标志
函数返回值:
    成功返回接收的字节数
    失败返回-1,并设置errno

完整流程

//todo tcp客户端,循环发送数据,接收回传数据
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>

#define N 128
//初始化socket
int  init_socket(char *ip,char *port){
   

    int init_socket_fd= socket(AF_INET,SOCK_STREAM,0);
    if (init_socket_fd==-1){
   
        printf("init_socket err");
        exit(EXIT_FAILURE);
    }

    struct sockaddr_in server_addr;
    socklen_t len=sizeof(server_addr);
    bzero(&server_addr,len);
    server_addr.sin_family=AF_INET;
    inet_aton(ip,&server_addr.sin_addr);
    server_addr.sin_port= htons(atoi(port));

    //连接
    int ret= connect(init_socket_fd,(struct sockaddr*)&server_addr,len);
    if (ret==-1){
   
        printf("connect error,连接失败\n");
        exit(EXIT_FAILURE);
    }


return init_socket_fd;
}

//客户端接收数据
int Client_Receive_data(int socket_fd){
   
    char receive_msg[N];
    bzero(receive_msg,N);
    int recv_len= recv(socket_fd, receive_msg,sizeof(receive_msg),0);
    if (recv_len == -1) {
   
        printf("recv error\n");
        exit(EXIT_FAILURE);
    }

    receive_msg[recv_len] = '\0';
    printf("收到客户端数据:[%s]\n",receive_msg);
}


//客户端发送数据
int  Client_Send_data(int socket_fd){
   
    char msg[N];

    while (1){
   
    bzero(&msg, sizeof (msg));
    printf("请输入:\n");
    fgets(msg, sizeof(msg),stdin);
    msg[strlen(msg)-1]='\0';

    printf("发送数据%s\n",msg);

    int  Send_data_len= send(socket_fd,&msg, strlen(msg),0);
        if (Send_data_len==-1){
   
            printf("发送失败 send err\n");
            exit(EXIT_FAILURE);
        }
    printf("发送了%d个字节\n",Send_data_len);

    if (strncmp(msg, "exit", 4) == 0) {
   
        printf("退出通信\n");
        close(socket_fd);
        break;
    }
    break;
    //接收
    Client_Receive_data(socket_fd);

    }

    return 0;
}

int main(){
   
    //初始化连接
    int socket_fd = init_socket("172.17.128.1","8888");
    //发送数据
    Client_Send_data(socket_fd);


    return 0;
}
相关文章
|
1天前
|
负载均衡 网络协议 算法
不为人知的网络编程(十九):能Ping通,TCP就一定能连接和通信吗?
这网络层就像搭积木一样,上层协议都是基于下层协议搭出来的。不管是ping(用了ICMP协议)还是tcp本质上都是基于网络层IP协议的数据包,而到了物理层,都是二进制01串,都走网卡发出去了。 如果网络环境没发生变化,目的地又一样,那按道理说他们走的网络路径应该是一样的,什么情况下会不同呢? 我们就从路由这个话题聊起吧。
16 4
不为人知的网络编程(十九):能Ping通,TCP就一定能连接和通信吗?
|
22天前
|
监控 网络协议 网络性能优化
网络通信的核心选择:TCP与UDP协议深度解析
在网络通信领域,TCP(传输控制协议)和UDP(用户数据报协议)是两种基础且截然不同的传输层协议。它们各自的特点和适用场景对于网络工程师和开发者来说至关重要。本文将深入探讨TCP和UDP的核心区别,并分析它们在实际应用中的选择依据。
51 3
|
2月前
|
Web App开发 缓存 网络协议
不为人知的网络编程(十八):UDP比TCP高效?还真不一定!
熟悉网络编程的(尤其搞实时音视频聊天技术的)同学们都有个约定俗成的主观论调,一提起UDP和TCP,马上想到的是UDP没有TCP可靠,但UDP肯定比TCP高效。说到UDP比TCP高效,理由是什么呢?事实真是这样吗?跟着本文咱们一探究竟!
66 10
|
1月前
|
网络协议 算法 网络性能优化
计算机网络常见面试题(一):TCP/IP五层模型、TCP三次握手、四次挥手,TCP传输可靠性保障、ARQ协议
计算机网络常见面试题(一):TCP/IP五层模型、应用层常见的协议、TCP与UDP的区别,TCP三次握手、四次挥手,TCP传输可靠性保障、ARQ协议、ARP协议
|
存储 C语言
《C语言及程序设计提高》网络课程主页
  在CSDN学院开出的网络系列课程《C语言及程序设计初步》已经完成(以后还将扩充)。   系列中的第二季《C语言及程序设计提高》的资源建设全部完成(视频资源链接)!   【公告】本课学员名单及QQ群公告,请到套餐主页查看。有兄弟,不孤单,一起营造学习氛围。   【重要通知1】自测题由于问卷星服务规则变化,不能看到答题情况,现转到“蓝墨云班课”中。加入方法:到mosoteach.cn免费注册账
1674 0
|
18天前
|
存储 C语言 开发者
【C语言】字符串操作函数详解
这些字符串操作函数在C语言中提供了强大的功能,帮助开发者有效地处理字符串数据。通过对每个函数的详细讲解、示例代码和表格说明,可以更好地理解如何使用这些函数进行各种字符串操作。如果在实际编程中遇到特定的字符串处理需求,可以参考这些函数和示例,灵活运用。
39 10
|
18天前
|
存储 程序员 C语言
【C语言】文件操作函数详解
C语言提供了一组标准库函数来处理文件操作,这些函数定义在 `<stdio.h>` 头文件中。文件操作包括文件的打开、读写、关闭以及文件属性的查询等。以下是常用文件操作函数的详细讲解,包括函数原型、参数说明、返回值说明、示例代码和表格汇总。
41 9
|
18天前
|
存储 Unix Serverless
【C语言】常用函数汇总表
本文总结了C语言中常用的函数,涵盖输入/输出、字符串操作、内存管理、数学运算、时间处理、文件操作及布尔类型等多个方面。每类函数均以表格形式列出其功能和使用示例,便于快速查阅和学习。通过综合示例代码,展示了这些函数的实际应用,帮助读者更好地理解和掌握C语言的基本功能和标准库函数的使用方法。感谢阅读,希望对你有所帮助!
31 8
|
18天前
|
C语言 开发者
【C语言】数学函数详解
在C语言中,数学函数是由标准库 `math.h` 提供的。使用这些函数时,需要包含 `#include <math.h>` 头文件。以下是一些常用的数学函数的详细讲解,包括函数原型、参数说明、返回值说明以及示例代码和表格汇总。
40 6
|
18天前
|
存储 C语言
【C语言】输入/输出函数详解
在C语言中,输入/输出操作是通过标准库函数来实现的。这些函数分为两类:标准输入输出函数和文件输入输出函数。
103 6
下一篇
DataWorks