【C++】6.网络编程:网络编程(TCP&UDP)

这篇具有很好参考价值的文章主要介绍了【C++】6.网络编程:网络编程(TCP&UDP)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

网络编程是C++ API操作中很重要的一部分,包含TCPUDP

网络传输模型可以抽象为7个层:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层

但在使用TCP/IP协议时,可以简化为这4层:网络接口、网络层、传输层、应用层

名词介绍

TCP:可靠传输,三次握手建立连接,传出去一定接受的到(如聊天软件);

UDP:不可靠传输,不需要建立连接,只管发送,实时性好(如视频会议);

套接字:表示通信的端点。就像用电话通信,套接字相当于电话,IP地址相当于总机号码,而端口号则相当于分机号码。

TCP

服务端创建流程:

  1. 调用socket函数创建监听socket
  2. 调用bind函数将socket绑定到某个IP和端口号组成的二元组上
  3. 调用listen函数开启监听
  4. 当有客户端连接请求时,调用accept函数接受连接,产生一个新的socket(与客户端通信的socket)
  5. 基于新产生的socket调用send或recv函数开始与客户端进行数据交流
  6. 通信结束后,调用close函数关闭socket

客户端创建流程:

  1. 调用socket函数创建客户端socket
  2. 调用connect函数尝试连接服务器
  3. 连接成功后调用send或recv函数与服务器进行数据交流
  4. 通信结束后,调用close函数关闭监听socket

服务端代码:

#include <iostream>
#include <sys/types.h>	//基本系统数据类型
#include <arpa/inet.h>	//网络信息转换
#include <unistd.h>		//POSIX系统API访问
#include <string.h>

using namespace std;
int main() {

    // 创建一个监听socket
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);	
	//常见的AF_INET──指定为IPv4协议,AF_INET6──指定为IPv6,AF_LOCAL──指定为UNIX 协议域
	//套接口可能的类型有:SOCK_STREAM字节流、SOCK_DGRAM数据报、SOCK_SEQPACKET有序分组、SOCK_RAW原始套接口
	//传输协议TCP/UDP,这里默认0
    if (listenfd == -1) {
        cout << " create listen socket error " << endl;
        return -1;
    }
    // 初始化服务器地址
    struct sockaddr_in bindaddr;
    bindaddr.sin_family = AF_INET;
    bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    bindaddr.sin_port = htons(8081);
	//如果只想在本机上进行访问,bind函数地址可以使用本地回环地址
	//如果只想被局域网的内部机器访问,那么bind函数地址可以使用局域网地址
	//如果希望被公网访问,那么bind函数地址可以使用INADDR_ANY or 0.0.0.0
    if (bind(listenfd, (struct sockaddr *)& bindaddr, sizeof(bindaddr)) == -1) {
        cout << "bind listen socket error" << endl;
        return -1;
    }
    // 启动监听
    if (listen(listenfd, SOMAXCONN) == -1) {
        cout << "listen error" << endl;
        return -1;
    }
	cout << "开始监听" << endl;

    while (true) {
        // 创建一个临时的客户端socket
        struct sockaddr_in clientaddr;
        socklen_t clientaddrlen = sizeof(clientaddr);
        // 接受客户端连接
        int clientfd = accept(listenfd, (struct sockaddr *)& clientaddr, &clientaddrlen);
        if (clientfd != -1) {
            char recvBuf[32] = {0};
            // 从客户端接受数据
            int ret = recv(clientfd, recvBuf, 32, 0);
            if (ret > 0) {
                cout << "recv data from cilent , data:" << recvBuf << endl;
                // 将接收到的数据原封不动地发给客户端
                ret = send(clientfd, recvBuf, strlen(recvBuf), 0);
                if (ret != strlen(recvBuf)) {
                    cout << "send data error" << endl;
                } else {
                    cout << "send data to client successfully, data " << recvBuf <<endl;
                }
            } else {
                cout << "recv data error" <<endl;
            }
            close(clientfd);
        }
    }

    // 关闭监听socket
    close(listenfd);
    return 0;
}


客户端代码:

#include <iostream>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>

#define SERVER_ADDRESS "127.0.0.1"
#define SERVER_PORT 8081
#define SEND_DATA "helloworld"

using namespace std;

int main() {
    // 创建一个socket
    int clientfd = socket(AF_INET, SOCK_STREAM, 0);
    if (clientfd == -1) {
        cout << " create client socket error " << endl;
        return -1;
    }
    // 连接服务器
    struct sockaddr_in serveraddr;
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(SERVER_ADDRESS);
    serveraddr.sin_port = htons(SERVER_PORT);
    if (connect(clientfd, (struct sockaddr *)& serveraddr, sizeof(serveraddr)) == -1) {
        cout << "connect socket error" << endl;
        return -1;
    }
    // 向服务器发送数据
    int ret = send(clientfd, SEND_DATA, strlen(SEND_DATA), 0);
    if (ret != strlen(SEND_DATA)) {
        cout << "send data error" << endl;
        return -1;
    } else {
        cout << "send data to client successfully, data " << SEND_DATA <<endl;
    }
    // 从服务器拉取数据
    char recvBuf[32] = {0};
    ret = recv(clientfd, recvBuf, 32, 0);
    if (ret > 0) {
        cout << "recv data to client successfully, data " << recvBuf <<endl;
    } else {
        cout << "recv data to client error" << endl;
    }
    // 关闭socket
    close(clientfd);
    return 0;
}

效果如下:

c++网络编程,c++基础与应用,网络,c++,tcp/ip

UDP

接收端创建流程:

  1. 创建套接字
  2. 将套接字绑定到一个本地地址和端口上(bind)
  3. 等待接受数据(recv)
  4. 关闭套接字。

发送端创建流程:

  1. 创建套接字
  2. 向服务器发送数据(send)
  3. 关闭套接字

UDP通信时,不强调server和client,重在实现两者互通;接收端需要bind,而发送端不需要。bind的一方只有接收到消息后才能开始发送。

设置两个端口实现互通:

接收端:

#include <sys/select.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <cstdlib>	//标准库头文件
#include <cstdio>	//c标准库
#include <cstring>	//c字符操作
#include <iostream>

int main(){

    //同一台电脑测试,需要两个端口
    int port_in  = 12321;
    int port_out = 12322;
    int sockfd;

    // 创建socket
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(-1==sockfd){
        return false;
        puts("Failed to create socket");
    }

    // 设置地址与端口
    struct sockaddr_in addr;
    socklen_t          addr_len=sizeof(addr);

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;       // Use IPV4
    addr.sin_port   = htons(port_out);    //
    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    // Time out
    struct timeval tv;
    tv.tv_sec  = 0;
    tv.tv_usec = 200000;  // 200 ms
    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(struct timeval));

    // Bind 端口,用来接受之前设定的地址与端口发来的信息,作为接受一方必须bind端口,并且端口号与发送方一致
    if (bind(sockfd, (struct sockaddr*)&addr, addr_len) == -1){
        printf("Failed to bind socket on port %d\n", port_out);
        close(sockfd);
        return false;
    }

    char buffer[128];
    memset(buffer, 0, 128);

    int counter = 0;
    while(1){
        struct sockaddr_in src;
        socklen_t src_len = sizeof(src);
        memset(&src, 0, sizeof(src));

        int sz = recvfrom(sockfd, buffer, 128, 0, (sockaddr*)&src, &src_len);
        if (sz > 0){
            buffer[sz] = 0;
            printf("Get Message %d: %s\n", counter++, buffer);
        }
        else{
            puts("timeout");
        }
    }

    close(sockfd);
    return 0;
}

发送端:

#include<sys/select.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <iostream>

int main(){
    int port_in  = 12321;
    int port_out = 12322;
    int sockfd;

    // 创建socket
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(-1==sockfd){
        return false;
        puts("Failed to create socket");
    }

    // 设置地址与端口
    struct sockaddr_in addr;
    socklen_t          addr_len=sizeof(addr);

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;       // Use IPV4
    addr.sin_port   = htons(port_in);    //
    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    // Time out
    struct timeval tv;
    tv.tv_sec  = 0;
    tv.tv_usec = 200000;  // 200 ms
    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(struct timeval));

    // 绑定获取数据的端口,作为发送方,不绑定也行
    if (bind(sockfd, (struct sockaddr*)&addr, addr_len) == -1){
        printf("Failed to bind socket on port %d\n", port_in);
        close(sockfd);
        return false;
    }

    int counter = 0;
    while(1){


        addr.sin_family = AF_INET;
        addr.sin_port   = htons(port_out);
        addr.sin_addr.s_addr = htonl(INADDR_ANY);

        sendto(sockfd, "hello world", 11, 0, (sockaddr*)&addr, addr_len);
        printf("Sended %d\n", ++counter);
        sleep(1);
    }

    close(sockfd);
    return 0;
}

设置一个端口实现互通:

接收端:

//只有在server接收到消息后才能实现互发数据
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#define SERVER_PORT 8888//唯一端口号
int main(){
    int ser_sockfd;
    int len;
    fd_set rfds;
    socklen_t addrlen;
    char seraddr[100];
    struct sockaddr_in ser_addr;
    int retval, maxfd;
    //建立socket
    ser_sockfd=socket(AF_INET,SOCK_DGRAM,0);
    if(ser_sockfd<0){
        printf("I cannot socket success\n");
        return 1;
     }
    //设置地址与端口
    addrlen=sizeof(struct sockaddr_in);
    bzero(&ser_addr,addrlen);
    ser_addr.sin_family=AF_INET;
    ser_addr.sin_addr.s_addr=htonl(INADDR_ANY);
    ser_addr.sin_port= htons (SERVER_PORT);
    //server绑定,才能接受client的数据
    if(bind(ser_sockfd,(struct sockaddr *)&ser_addr,addrlen)<0){
        printf("connect");
        return 1;
    }
    while(1){
        bzero(seraddr,sizeof(seraddr));
        len=recvfrom(ser_sockfd,seraddr,sizeof(seraddr),0,(struct sockaddr*)&ser_addr,&addrlen);
        /*显示client端的网络地址*/
        printf("receive from %s\n",inet_ntoa(ser_addr.sin_addr));
        /*显示客户端发来的字串*/
        printf("recevce:%s",seraddr);
        /*输入字串返回给client端*/
        while(1)
        {
             /*把可读文件描述符的集合清空*/
             FD_ZERO(&rfds);
             /*把标准输入的文件描述符加入到集合中*/
             FD_SET(0, &rfds);
             maxfd = 0;
             /*把当前连接的文件描述符加入到集合中*/
             FD_SET(ser_sockfd, &rfds);
             /*找出文件描述符集合中最大的文件描述符*/
             if(maxfd < ser_sockfd)
                maxfd = ser_sockfd;
             retval = select(maxfd+1, &rfds, NULL, NULL, NULL);
             if(FD_ISSET(ser_sockfd,&rfds))//client发消息来会出发进入
             {
             len=recvfrom(ser_sockfd,seraddr,sizeof(seraddr),0,(struct sockaddr*)&ser_addr,&addrlen);                   printf("recevce:%s",seraddr);
              }
                 if(FD_ISSET(0, &rfds))//键盘输入会触发进入
                 {
                     len=read(STDIN_FILENO,seraddr,sizeof(seraddr));
                     sendto(ser_sockfd,seraddr,len,0,(struct sockaddr*)&ser_addr,addrlen);
                 }
        }
    }
    return 0;
}

发送端:

#include <netinet/in.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <arpa/inet.h>
#define SERVER_PORT 8888   //唯一端口
int main(int argc,char **argv){
    int cli_sockfd;
    int len;
    fd_set rfds;
    socklen_t addrlen;
    struct sockaddr_in cli_addr;
    char buffer[256];
    char buffer1[256];
    int retval, maxfd;
    //创建socket
    cli_sockfd=socket(AF_INET,SOCK_DGRAM,0);
    if(cli_sockfd<0){
        printf("I cannot socket success\n");
        return 1;
    }
    //配置地址与端口
    addrlen=sizeof(struct sockaddr_in);
    bzero(&cli_addr,addrlen);
    cli_addr.sin_family=AF_INET;
    cli_addr.sin_addr.s_addr=htonl(INADDR_ANY);//任何主机地址
    cli_addr.sin_port=htons(SERVER_PORT);
	//这里作为发送方,不需要绑定bind()
    while(1)
    {
        bzero(buffer,sizeof(buffer));
        /* 从标准输入设备取得字符串*/   len=read(STDIN_FILENO,buffer,sizeof(buffer));
        /* 将字符串传送给server端*/
        sendto(cli_sockfd,buffer,len,0,(struct sockaddr*)&cli_addr,addrlen);
        /* 接收server端返回的字符串*/
        while(1)
        {
                     /*把可读文件描述符的集合清空*/
                     FD_ZERO(&rfds);
                     /*把标准输入的文件描述符加入到集合中*/
                     FD_SET(0, &rfds);
                     maxfd = 0;
                     /*把当前连接的文件描述符加入到集合中*/
                     FD_SET(cli_sockfd, &rfds);
                     /*找出文件描述符集合中最大的文件描述符*/
                     if(maxfd < cli_sockfd)
                         maxfd = cli_sockfd;

                     retval = select(maxfd+1, &rfds, NULL, NULL, NULL);

                    if(FD_ISSET(cli_sockfd,&rfds))//server发来数据将会触发进入循环
                    {

                        len=recvfrom(cli_sockfd,buffer1,sizeof(buffer1),0,(struct sockaddr*)&cli_addr,&addrlen);
                        printf("receive: %s",buffer1);
                    }
                     if(FD_ISSET(0, &rfds))//键盘输入会触发进入
                     {
                         len=read(STDIN_FILENO,buffer,sizeof(buffer));
                         sendto(cli_sockfd,buffer,len,0,(struct sockaddr*)&cli_addr,addrlen);
                     }

        }
    }
    close(cli_sockfd);
    return 0;
}

c++网络编程,c++基础与应用,网络,c++,tcp/ip

c++网络编程,c++基础与应用,网络,c++,tcp/ip

以上。文章来源地址https://www.toymoban.com/news/detail-561211.html

到了这里,关于【C++】6.网络编程:网络编程(TCP&UDP)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++网络编程 TCP套接字基础知识,利用TCP套接字实现客户端-服务端通信

    流式套接字编程针对TCP协议通信,即是面向对象的通信,分为服务端和客户端两部分。 1)加载套接字库( 使用函数WSAStartup() ),创建套接字( 使用socket() ) 2)绑定套接字到一个IP地址和一个端口上( 使用函数bind() ) 3)将套接字设置为监听模式等待连接请求( 使用函数

    2024年02月03日
    浏览(46)
  • 初学记录【linux应用】 TCP/UDP 网络编程 C语言

    以下内容分别为TCP 与 UDP编程,内容有相似或者重合部分,可根据流程 相互对照学习,都已经附上源码 。 **1.** socket 创建 tcp套接字 (监听的套接字) 2、IPv4套接字地址结构 #include netinet/in.h struct in_addr: 如果使用 Internet 所以 sin_family 一般为 AF_INET。 ⚫ sin_addr 设置为 INADDR_AN

    2024年02月03日
    浏览(57)
  • [C++ 网络协议编程] UDP协议

    目录 1. UDP和TCP的区别 2. UDP的工作原理 3. UDP存在数据边界 4. UDP的I/O函数 4.1 sendto函数 4.2 recvfrom函数 4. 已连接(connected)UDP套接字和未连接(unconnected)UDP套接字 5. UDP的通信流程 5.1 服务器端通信流程 5.2 客户端通信流程 主要区别: TCP和UDP的主要区别是,TCP具有流控制机制,而UDP没

    2024年02月12日
    浏览(38)
  • Java网络编程基础:TCP Socket套接字编程 IntAddress UDP等...

    目录 一,网络基础 1.IP地址 2.端口 3.TCP/UDP协议 4.网络编程开发模式  二,基于套接字的Java网络编程 1.Socket  2.InetAddress 三.基于TCP的Socket网络编程 1.单服务器端与单Socket客户端一次通讯 2.单服务器端接收多次通讯  3.TCP网络通讯补充 四,基于UDP的网络编程 1. DatagramSocket:收发

    2024年04月29日
    浏览(38)
  • 网络编程套接字应用分享【Linux &C/C++ 】【UDP应用 | TCP应用 | TCP&线程池小项目】

    目录 前提知识 1. 理解源ip,目的ip和Macip 2. 端口号 3. 初识TCP,UDP协议 4. 网络字节序 5. socket 编程 sockaddr类型  一,基于udp协议编程  1. socket——创建套接字 2. bind——将套接字强绑定  3. recvfrom——接受数据 4. sendto——发出信息  遇到的问题 (1. 云服务器中以及无法分配I

    2024年04月08日
    浏览(81)
  • Java-Java基础学习(2)-网络编程-TCP-UDP

    2.1. 通信协议 TCP、UDP对比 TCP 打电话 连接,稳定 三次握手,四次挥手 客户端、服务端 传输完成,释放连接,效率低 UDP 发短信 不连接,不稳定 客户端,服务端,没有明确的界限 不管有没有准备好,都可以发给你 导弹 DDOS:洪水供给!(饱和攻击) 2.2. Tcp上传测试 总结:

    2024年04月09日
    浏览(41)
  • Linux网络编程——C++实现进程间TCP/IP通信

    地址接口 1、通用地址接口 共16字节 = 2字节地址类型 + 14字节地址数据 2、自定义地址接口 地址转换 1、需要将点分字符串ip转化为程序ip,使用inet_addr函数: 2、字节序转换 地址接口配置中的端口需要字节序转换,网络规定使用大端字节序。 地址接口配置 1、socket:创建套接

    2024年02月20日
    浏览(49)
  • 【socket】从计算机网络基础到socket编程——Windows && Linux C语言 + Python实现(TCP+UDP)

    简单讲一下基础知识,便于后面代码的理解,建议大概浏览一下这一小节内容。这里讲的只是冰山一角,建议大家学习计算机网络相关知识,推荐几本书: 《计算机网络》(谢希仁) 《计算机网络 自顶向下方法》 《计算机网络技术》 《计算机网络基础及应用》 《Linux C从入

    2024年02月08日
    浏览(51)
  • 网络编程 —— TCP 和 UDP 编程详解

    目录 网络编程主要函数介绍 1. socket 函数 2. bind 函数 3. listen 函数 4. accept 函数 5. connect 函数 6. send 函数 7. recv 函数 8. recvfrom 函数 9. sendto 函数 TCP 和 UDP 原理上的区别 TCP 编程 服务端代码: 客户端代码: UDP 编程 服务端代码: 客户端代码: 1. socket 函数 int socket(int domain, int

    2024年02月04日
    浏览(38)
  • 网络编程、UDP、TCP

    就是将地理位置不同的具有独立功能的多台计算及外部设备,通过通信线路连接起来,在网络操作系统、网络管理软件以及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统 传播交流信息、数据交换、通信 1.如何准确定位网络上的一台主机 192.xxx.xx.xx:端

    2024年03月10日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包