C语言 网络编程(十一)TCP通信创建流程---服务端

简介: 在服务器流程中,新增了绑定IP地址与端口号、建立监听队列及接受连接并创建新文件描述符等步骤。`bind`函数用于绑定IP地址与端口,`listen`函数建立监听队列并设置监听状态,`accept`函数则接受连接请求并创建新的文件描述符用于数据传输。套接字状态包括关闭(CLOSED)、同步发送(SYN-SENT)、同步接收(SYN-RECEIVE)和已建立连接(ESTABLISHED)。示例代码展示了TCP服务端程序如何初始化socket、绑定地址、监听连接请求以及接收和发送数据。

服务端流程

img_88.png

在上述流程中,相对于客户端主要增加以下新的流程
bind : 绑定 ip 地址与端⼝号,⽤于客户端连接服务器
listen : 建⽴监听队列,并设置套接字的状态为 listen 状态, 表示可以接收连接请求
accept : 接受连接, 建⽴三次握⼿, 并创建新的⽂件描述符, ⽤于数据传输

socket 套接字状态如下图:
img_89.png

CLOSED : 关闭状态
SYN-SENT : 套接字正在试图主动建⽴连接 [发送 SYN 后还没有收到 ACK],很短暂
SYN-RECEIVE : 正在处于连接的初始同步状态 [收到对⽅的 SYN,但还没收到⾃⼰发过去的SYN 的 ACK]
ESTABLISHED : 连接已建⽴

bind 函数 绑定 ip 地址与端⼝号,

函数头文件:
#include <sys/types.h>
#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

函数功能:
绑定 ip 地址与端⼝号, 使得套接字可以接收客户端的连接请求

参数:
sockfd : 套接字描述符
addr : 指向 sockaddr 结构体的指针, 包含了要绑定的 ip 地址和端⼝号
addrlen : 结构体 sockaddr 的长度

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

在服务器绑定 ip 地址与端⼝号之后, 则需要让服务器 socket 套接字设置成被动监听状态,并
创建监听队列,这⾥需要调⽤ listen 函数

listen 函数 建⽴监听队列

函数头文件:
#include <sys/types.h>
#include <sys/socket.h>

int listen(int sockfd, int backlog);

函数功能:
建⽴监听队列, 并设置套接字的状态为 listen 状态, 表示可以接收连接请求

参数:
sockfd : 套接字描述符
backlog : 监听队列的最大长度

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

在服务器端调用 listen 函数之后, 则可以开始接收客户端的连接请求, 并创建新的套接字
用于数据传输, 这⾥需要调⽤ accept 函数

accept 函数 接受连接, 建⽴三次握⼿, 并创建新的⽂件描述符, ⽤于数据传输

函数头文件:
#include <sys/types.h>
#include <sys/socket.h>


int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

函数功能:
接受连接, 建⽴三次握⼿, 并创建新的⽂件描述符, ⽤于数据传输

参数:
sockfd : 套接字描述符
addr : 指向 sockaddr 结构体的指针, 用于返回客户端的 ip 地址和端⼝号
addrlen : 指向 socklen_t 类型的指针, 用于返回 sockaddr 结构体的长度

返回值:
成功 : 新的套接字描述符
失败 : -1, 并设置 errno 变量

在服务器端调用 accept 函数之后, 则可以接收客户端的连接请求, 并创建新的套接字用于数据
传输, 调⽤ recv 和 send 函数进行数据传输

// 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 bind_ret= bind(init_socket_fd,(struct sockaddr*)&server_addr,len);
    if (bind_ret == -1) {
   
   
        printf("bind error\n");
        exit(EXIT_FAILURE);
    }

    int listen_ret= listen(init_socket_fd,10);
    if (listen_ret == -1) {
   
   
        printf("listen error\n");
        exit(EXIT_FAILURE);
    }


    return init_socket_fd;
}

//客户端发送消息
int  Server_Send_data(int clientFD,char* msg){
   
   
    strcat(msg,"-回传");


    int server_send_len=send(clientFD,msg,strlen(msg),0);
    if (server_send_len == -1) {
   
   
        printf("send error\n");
        exit(EXIT_FAILURE);
    }if (server_send_len == 0) {
   
   
        printf("客户端关闭连接\n");
        return -1;
    }
    printf("发送给客户端数据:[%s]\n",msg);
    return 0;
}


//接收数据
int Server_Receive_data(int clientFD){
   
   
    while (1){
   
   
        //接收-使用新的文件描述符
        char recv_buf[N];
        bzero(recv_buf, sizeof(recv_buf));
        int recv_len = recv(clientFD, recv_buf, sizeof(recv_buf), 0);
        if (recv_len == -1) {
   
   
            printf("recv error\n");
            exit(EXIT_FAILURE);
        }
        if (recv_len == 0) {
   
   
            printf("客户端关闭连接\n");
            break;
        }
        if (strncmp(recv_buf, "exit", 4) == 0) {
   
   
            printf("客户端退出通信\n");
            close(clientFD);
            break;
        }
        printf("收到客户端消息:|%s|\n",recv_buf);

        Server_Send_data(clientFD, recv_buf);
    }
    return 0;
}



int main(){
   
   

    int socket_fd = init_socket("172.17.140.183","8080");

    struct sockaddr_in cli_addr;
    socklen_t cli_len=sizeof(cli_addr);

    //获取客户端连接
    int clientFD= accept(socket_fd,(struct sockaddr*)&cli_addr,&cli_len);
    if (clientFD == -1){
   
   
        printf("accept error\n");
        exit(EXIT_FAILURE);
    }

    printf("连接 ip:%s, port:%d\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port));

    //接收数据
    Server_Receive_data(clientFD);


    //关闭连接
    close(clientFD);
}
相关文章
|
3天前
|
负载均衡 网络协议 算法
不为人知的网络编程(十九):能Ping通,TCP就一定能连接和通信吗?
这网络层就像搭积木一样,上层协议都是基于下层协议搭出来的。不管是ping(用了ICMP协议)还是tcp本质上都是基于网络层IP协议的数据包,而到了物理层,都是二进制01串,都走网卡发出去了。 如果网络环境没发生变化,目的地又一样,那按道理说他们走的网络路径应该是一样的,什么情况下会不同呢? 我们就从路由这个话题聊起吧。
18 4
不为人知的网络编程(十九):能Ping通,TCP就一定能连接和通信吗?
|
25天前
|
安全 搜索推荐 网络安全
HTTPS协议是**一种通过计算机网络进行安全通信的传输协议
HTTPS协议是**一种通过计算机网络进行安全通信的传输协议
53 11
|
22天前
|
网络协议
计算机网络与通信
计算机网络基本概念:了解计算机网络的定义、功能、分类和拓扑结构(如总线型、星型、环型、树形、网状等)。 网络通信原理:了解网络通信的基本原理、协议和技术,如TCP/IP协议、网络通信设备等。
25 3
|
23天前
|
网络协议 物联网 数据处理
C语言在网络通信程序实现中的应用,介绍了网络通信的基本概念、C语言的特点及其在网络通信中的优势
本文探讨了C语言在网络通信程序实现中的应用,介绍了网络通信的基本概念、C语言的特点及其在网络通信中的优势。文章详细讲解了使用C语言实现网络通信程序的基本步骤,包括TCP和UDP通信程序的实现,并讨论了关键技术、优化方法及未来发展趋势,旨在帮助读者掌握C语言在网络通信中的应用技巧。
35 2
|
27天前
|
存储 网络协议 物联网
C 语言物联网开发之网络通信与数据传输难题
本文探讨了C语言在物联网开发中遇到的网络通信与数据传输挑战,分析了常见问题并提出了优化策略,旨在提高数据传输效率和系统稳定性。
|
1月前
|
算法
数据结构之卫星通信网络(BFS)
本文介绍了卫星通信网络及其重要性,并探讨了广度优先搜索(BFS)算法在其中的应用。卫星通信网络通过在轨卫星提供全球覆盖的通信服务,尤其在偏远地区和紧急救援中发挥关键作用。BFS算法用于网络拓扑分析、路径规划和故障排除,确保通信网络的高效运行。文章还包括BFS算法的工作原理、特点、优缺点及其实现代码示例。
40 1
|
1月前
|
传感器 自动驾驶 物联网
探秘 5G 核心网络之 5G RAN:开启高速通信新时代
探秘 5G 核心网络之 5G RAN:开启高速通信新时代
63 4
|
1月前
|
物联网 5G 数据中心
|
1月前
|
网络协议 算法 数据库
OSPF 与 BGP 的互操作性:构建复杂网络的通信桥梁
OSPF 与 BGP 的互操作性:构建复杂网络的通信桥梁
39 0
|
1月前
|
边缘计算 5G 数据处理
5G网络能耗管理:绿色通信的实践
【10月更文挑战第30天】
44 0
下一篇
DataWorks