网络编程基础之TCP基本通信

TCP特性

TCP(Transmission Control Protocol,传输控制协议) ,是TCP/IP协议族中用于传输层 的协议,特点是面向连接、可靠、基于字节流,能够保障数据不丢失、重复、无序,但数据传输效率较低,且数据收发不同步。

TCP服务器端代码实现

cpp 复制代码
//服务器端代码实现
#include <stdio.h>    // printf
#include <iostream>    // std::cout
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>    //定义socket相关的函数和数据结构
#include <sys/types.h>    //系统基础数据类型定义头文件(定义Unix/Linux 系统中用于描述「对象类型」的基本数据类型)
#include <string.h>    //调strcat bzero strlen函数
#include <unistd.h>    //调close函数
#define SERVER_PORT 8888    //服务器端口号
#define SERVER_IP "192.168.23.128"    //服务器端IP地址

int main(){
    //1.创建用于连接的套接字文件描述符--socket
    int sfd = socket(AF_INET,SOCK_STREAM,0);    //sfd全称socket file descriptor(套接字文件描述符)
    //参数1:AF_INET表示使用IPv4协议族
    //参数2:SOCK_STREAM表示使用面向连接的TCP协议
    //参数3:协议类型,通常设置为0,表示使用默认协议(参数2指定了协议时参数3填写0即可)
    //返回值:成功返回sfd(socket文件描述符),失败返回-1
    if(sfd == -1){
        perror("socket error");
        return -1;
    }
    printf("socket success sfd = %d\n",sfd);


    //2.绑定ip地址和端口号--bind
    //2.1填充要绑定的ip地址和端口号结构体
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;    //通信域
    sin.sin_port = htons(SERVER_PORT);    //端口号(使用htons将2字节整数转换为网络字节序)
    sin.sin_addr.s_addr = inet_addr(SERVER_IP);    //IP地址(使用inet_addr将点分十进制字符串转换为网络字节序)
    
    //2.2绑定工作
    //参数1:要被绑定的套接字文件描述符
    //参数2:要绑定的地址信息结构体,需要进行强制类型转换,防止警告
    //参数3:参数2的大小
    //返回值:成功返回0,失败返回-1并置位错误码
    if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin)) == -1){
        perror("bind error");
        return -1;
    }
    printf("bind success\n");


    //3.启动监听--listen
    //参数1:要启动监听的文件描述符
    //参数2:挂起队列的长度
    //返回值:成功返回0,失败返回-1并置位错误码
    if(listen(sfd, 128) == -1){
        perror("listen error");
        return -1;
    }
    printf("listen success\n");


    //4.阻塞等待客户端的连接请求--accept
    //定义变量用于接收客户端地址信息结构体
    struct sockaddr_in cin;    //用于接收地址信息结构体
    socklen_t socklen = sizeof(cin);    //用于接收地址信息的长度

    //参数1:服务器套接字文件描述符
    //参数2:用于接收客户端地址信息结构体的容器,如果不接收,也可以填NULL
    //参数3:接收参数2的大小,如果参数2为NULL,则参数3也是NULL
    //返回值:成功则返回一个新的用于通信的套接字文件描述符(即newfd),失败返回-1并置位错误码
    int newfd = accept(sfd, (struct sockaddr*)&cin, &socklen);    //新的用于通信的套接字文件描述符
    if(newfd == -1){
        perror("accept error");
        return -1;
    }
    printf("[%s:%d]已连接成功!\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port));    //客户端IP地址 客户端端口号


    //5.数据收发--recv/send
    char rbuf[128] = "";    //数据容器
    while(1){
        //清空容器中的内容
        bzero(rbuf,sizeof(rbuf));

        //从套接字中读取消息--recv
        //参数1:通信的套接字文件描述符
        //参数2:要存放数据的起始地址
        //参数3:读取的数据的大小
        //参数4:读取标识位,是否阻塞读取(0表示阻塞等待,MSG_DONTWAIT表示非阻塞)
        //返回值:大于0表示成功读取的字节个数,等于0表示对端已下线,等于-1表示失败,并置位错误码
        int res = recv(newfd, rbuf, sizeof(rbuf), 0);
        if(res == 0){
            printf("对端已下线\n");
            break;
        }
        printf("[%s:%d]:%s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), rbuf);    //客户端IP地址 客户端端口号
    
        //处理收到的数据并送回给客户端
        strcat(rbuf, "_");

        //将消息发送给客户端--send
        //参数1:通信的套接字文件描述符
        //参数2:要发送的数据的起始地址
        //参数3:发送的数据的大小
        //参数4:读取标识位,是否阻塞读取(0表示阻塞等待,MSG_DONTWAIT表示非阻塞)
        //返回值:大于0表示成功发送的字节个数,等于0表示对端已下线,等于-1表示失败,并置位错误码
        if(send(newfd, rbuf, strlen(rbuf), 0) == -1){
            perror("send error");
            return -1;
        }
        printf("发送成功!\n");
    }


    //6.关闭套接字--close
    //参数:要关闭的套接字文件描述符,类型为int
    //返回值:成功返回0,失败返回-1并置位错误码
    close(newfd);
    close(sfd);

    return 0;
}

TCP客户端代码实现

cpp 复制代码
//客户端代码实现
#include <stdio.h>    // printf
#include <iostream>    // std::cout
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>    //定义socket相关的函数和数据结构
#include <sys/types.h>    //系统基础数据类型定义头文件(定义Unix/Linux 系统中用于描述「对象类型」的基本数据类型)
#include <string.h>    //调strcat bzero strlen函数
#include <unistd.h>    //调close函数
#define SERVER_PORT 8888    //服务器端口号
#define SERVER_IP "192.168.23.128"    //服务器端IP地址
#define CLIENT_PORT 9999    //客户端口号
#define CLIENT_IP "192.168.23.128"    //客户端IP地址

int main(){
    //1.创建用于连接的套接字文件描述符--socket
    int cfd = socket(AF_INET,SOCK_STREAM,0);    //客户套接字文件描述符
    if(cfd == -1){
        perror("socket error");
        return -1;
    }
    printf("socket success cfd = %d\n",cfd);


    //2.绑定ip地址和端口号--bind
    //2.1填充要绑定的ip地址和端口号结构体
    struct sockaddr_in cin;
    cin.sin_family = AF_INET;    //通信域
    cin.sin_port = htons(CLIENT_PORT);    //端口号(使用htons将2字节整数转换为网络字节序)
    cin.sin_addr.s_addr = inet_addr(CLIENT_IP);    //IP地址(使用inet_addr将点分十进制字符串转换为网络字节序)
    
    //2.2绑定工作(可选)
    if(bind(cfd,(struct sockaddr*)&cin,sizeof(cin)) == -1){
        perror("bind error");
        return -1;
    }
    printf("bind success\n");


    //3.连接服务器--connect
    //3.1填充要连接的服务器地址信息结构体
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;    //通信域
    sin.sin_port = htons(SERVER_PORT);    //端口号
    sin.sin_addr.s_addr = inet_addr(SERVER_IP);    //服务器端IP地址

    //3.2连接工作
    //参数1:要连接的套接字文件描述符
    //参数2:通用地址信息结构体
    //参数3:参数2的大小
    //返回值:成功返回0,失败返回-1并置位错误码
    if(connect(cfd, (struct sockaddr*)&sin, sizeof(sin)) == -1){
        perror("connect error");
        return -1;
    }
    printf("连接服务器成功!\n");


    //4.数据收发--recv/send
    char wbuf[128] = "";    //数据容器
    while(1){
        //清空容器中的内容
        bzero(wbuf,sizeof(wbuf));

        //从终端获取数据
        fgets(wbuf, sizeof(wbuf), stdin);
        wbuf[strlen(wbuf) - 1] = 0;    //将换行改成'\0'

        //将数据发送给服务器
        if(send(cfd, wbuf, sizeof(wbuf), 0) == -1){
            perror("send error");
            return -1;
        }

        //接收服务器发送过来的消息
        if(recv(cfd, wbuf, sizeof(wbuf), 0) == 0){
            printf("对端已经下线\n");
            break;
        }
        printf("收到服务器消息为:%s\n", wbuf);
    }


    //5.关闭套接字--close
    close(cfd);

    return 0;
}
相关推荐
Utopia^2 小时前
Flutter 框架跨平台鸿蒙开发 - 时光倒流
服务器·flutter·华为·harmonyos
自动化测试行业观察2 小时前
2026年第1季度全国网速实测报告
网络
婷婷_1722 小时前
【PCIe 验证每日学习・Day26】PCIe 错误处理与异常恢复机制
网络·学习·程序人生·芯片·原子操作·pcie 验证
清空mega2 小时前
动手学深度学习|批量归一化(Batch Normalization)超详细讲解:为什么它能让深层网络更容易训练?
网络·深度学习·batch
熊明才3 小时前
PM2 服务器服务运维入门指南
运维·服务器·windows
CHANG_THE_WORLD3 小时前
PDFIUM如何处理宽度数组
java·linux·服务器
FreeBuf_3 小时前
14000余台F5 BIG-IP暴露,高危RCE漏洞正遭活跃利用
tcp/ip·安全·web安全
孙同学_3 小时前
【Linux篇】应用层自定义协议与序列化
linux·服务器·网络
航Hang*3 小时前
第3章:Linux系统安全管理——第1节:Linux 防火墙部署(firewalld)
linux·服务器·网络·学习·系统安全·vmware