当前位置: 首页 > news >正文

网络编程 -------- 3、TCP_UDP_UNIX

1、基于TCP的套接字编程流程 

    Server.c 
        socket 
        bind  (服务器的ip+端口)
        listen
        accept
        recv / send
        close

    Client.c 
        socket 
        connect (服务器的ip+端口)
        send / recv
        close

扩展:

        (1) 三路握手: TCP建立连接时
                1)SYN请求 (客户端-->服务器) 
                2)SYN+ACK应答 (服务器-->客户端) 
                3)ACK确认 (客户端-->服务器)


        (2) 四次挥手: TCP断开连接时 
                1)FIN请求 (客户端-->服务器)
                2)ACK应答 (服务器-->客户端)
                3)FIN请求 (服务器-->客户端)
                4)ACK应答 (客户端-->服务器)

2、基于UDP的套接字编程流程 

    Server.c 
        socket  
        bind  (服务器的ip+端口)
        recvfrom / sendto
        close

    Client.c 
        socket 
        //设置服务器的ip和端口
        sendto / recvfrom
        close

利用UDP 实现简单的通信   UDP ---> SOCK_DGRAM 数据报套接字类型udp_server.c   接收数据 int main( int argc, char *argv[] ){//1.创建套接字 UDP ---> SOCK_DGRAM 数据报套接字int server_fd = socket( AF_INET, SOCK_DGRAM, 0 );if( server_fd == -1 ){perror("socket server error ");return -1;}printf("server_fd = %d\n", server_fd );//2.绑定服务器的ip和端口struct sockaddr_in  server_addr;server_addr.sin_family = AF_INET;           //协议族 server_addr.sin_port = htons( atoi(argv[2]) );    //端口号inet_aton( argv[1], &server_addr.sin_addr );  //IP地址int re = bind( server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr) );if( re == -1 ){perror("bind server error ");return -1;}printf("bind server success\n");//3.通信 while( 1 ){//接收数据 char buf[128] = {0};struct sockaddr_in  client_addr;socklen_t len = sizeof(client_addr);re = recvfrom( server_fd, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr, &len );if( re >= 0 ){printf("%s : %s\n", inet_ntoa(client_addr.sin_addr), buf );}else {perror("recvfrom server error ");break;}//人为定义退出条件if( buf[0] == '#' ){break;}}//4.关闭套接字close( server_fd );}udp_client.c   发送数据  int main( int argc, char *argv[] ){//1.创建套接字 UDP ---> SOCK_DGRAM 数据报套接字int client_fd = socket( AF_INET, SOCK_DGRAM, 0 );if( client_fd == -1 ){perror("socket client error ");return -1;}printf("client_fd = %d\n", client_fd );//2.设置服务器的ip和端口struct sockaddr_in  server_addr;server_addr.sin_family = AF_INET;           //协议族 server_addr.sin_port = htons( atoi(argv[2]) );    //端口号inet_aton( argv[1], &server_addr.sin_addr );  //IP地址//3.通信 while(1){//发送数据 char buf[128] = {0};printf("input data : ");fgets(buf, sizeof(buf), stdin);int re = sendto( client_fd, buf, strlen(buf), 0, (struct sockaddr *)&server_addr, sizeof(server_addr) );if( re == -1 ){perror("sendto error ");break;}//人为定义退出条件if( buf[0] == '#' ){break;}}//4.关闭套接字close( client_fd );}

            

3、UNIX域协议

        UNIX域协议是利用socket编程接口 来实现 本地进程之间(客户端/服务器)的通信,它是进程间通信(IPC)的一种方式。它使用文件系统中的路径名来标识服务器和客户端。

        UNIX域协议的套接字: 
            SOCK_STREAM     --->  TCP 面向字节流 
            SOCK_DGRAM      --->  UDP 面向数据报  

        其编程接口 和 流程 与 ipv4协议族是一样的
        只不过 协议族为 AF_UNIX , 对应的地址结构体为 

            UNIX域协议地址结构体 ( man 7 unix )
                    #include <sys/un.h>

                struct sockaddr_un 
                {
                    sa_family_t  sun_family;        /* 协议族 AF_UNIX */
                    char         sun_path[108];     /* UNIX域协议的地址,在本地文件系统中的“绝对路径名” pathname */
                };

            #define UNIX_PATH  "/home/china/unix2418F"

        实现方法:  UDP / TCP 
       

练习: 利用UNIX域协议 实现简单的通信 (以UDP为例)unix_server.c   接收数据 int main( int argc, char *argv[] ){//删除 unlink( UNIX_PATH );//1.创建套接字 AF_UNIX  int server_fd = socket( AF_UNIX, SOCK_DGRAM, 0 );if( server_fd == -1 ){perror("socket server error ");return -1;}//2.绑定 服务器的地址 struct sockaddr_un  server_addr;server_addr.sun_family = AF_UNIX;           //协议族 strcpy( server_addr.sun_path, UNIX_PATH );  //unix域协议的地址int re = bind( server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr) );if( re == -1 ){perror("bind server error ");close( server_fd );return -1;}printf("bind server success\n");struct sockaddr_un  client_addr;socklen_t len = sizeof(client_addr);//3.通信 while(1){//接收数据 char buf[128] = {0};re = recvfrom( server_fd, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr, &len );if( re >= 0 ){printf("recv : %s\n", buf );}else {perror("recvfrom server error ");break;}if( buf[0] == '#' ){break;}}//4.关闭套接字close( server_fd );}unix_client.c   发送数据  //1.创建套接字 //2.设置服务器的地址 //3.通信 //4.关闭套接字


4、套接字选项  

    套接字选项是用来设置或获取套接字的一些特性的选项。

        每个套接字在不同的层次上(级别) 有不同的行为属性(选项) 

        有两个接口函数用来 获取和设置 套接字的选项: 

            getsockopt 
            setsockopt  

                NAME
                    getsockopt, setsockopt - get and set options on sockets
                SYNOPSIS
                    #include <sys/types.h>          /* See NOTES */
                    #include <sys/socket.h>

                    int getsockopt(int sockfd, int level, int optname,
                                    void *optval, socklen_t *optlen);
                    int setsockopt(int sockfd, int level, int optname,
                                    const void *optval, socklen_t optlen); 
                        功能:获取/设置套接字的选项 
                        参数: 
                            sockfd:指定要操作的套接字描述符 
                            level:级别,不同的选择在不同的级别上(查看资料)
                            optname:选项名 
                            optval: 通用指针 
                                        get 用来保存获取到的选项值 
                                        set 用来保存要设置的选项值 
                                             不同的选项 对应的类型是不一样的 
                                                如果为 int  ---> 0  禁用选项 
                                                            --> 非0 使能选项 
                            optlen: 
                                    get 指针,指向空间保存选项值的空间的长度 
                                    set 变量,用来指定要设置的选项值的长度 
                        返回值: 
                            成功,返回0
                            失败,返回-1,同时errno被设置
                     

设置 端口号重用 选项名: SO_REUSEPORT 级别:  SOL_SOCKET值的类型: int /设置端口号重用 int n = 1;setsockopt( server_sock, SOL_SOCKET, SO_REUSEPORT, &n, sizeof(n) );

5、UDP的例子 (拓展)

    1)DNS : Domain Name System 域名系统  

            www.baidu.com  ----> 域名  

            DNS:是把一个域名 转换成 相应的ip地址的服务  

            DNS协议 传输层用到UDP协议 
                    DNS Server  
                        ip: 114.114.114.114 
                        端口  53

  
    2)NTP : Network Time Protocol 网络时间协议

  
            基于UDP的传输层协议 

                服务器: 
                    阿里云 :  182.92.12.11
                    端口: 123      

        利用TCP 写一个网络传输文件的程序  file_tcp_server.c   服务器 接收文件  file_tcp_client.c   客户端 发送文件  注意: 通信双方 发送和接收的 数据、大小、顺序 要保持一致 遵守通信双向的约定 ---> "协议"file_tcp_server.c   服务器 接收文件  int recv_file( int sock_fd ){//切换路径 chdir("../");//接收文件名的长度大小 int name_len = 0;int re = recv( sock_fd, &name_len, sizeof(name_len), 0 );if( re == -1 ){perror("recv name_len error "); return -1;}printf("recv name_len success , len = %d\n", name_len );//接收文件名char filename[128] = {0};re = recv( sock_fd, filename, name_len, 0 );if( re == -1 ){perror("recv filename error ");return -1;}printf("recv filename success , filename = %s\n", filename );//接收文件的大小 int file_size = 0;re = recv( sock_fd, &file_size, sizeof(file_size), 0 );if( re == -1 ){perror("recv file_size error ");return -1;}printf("recv file_size success , file_size = %d\n", file_size );/* 接收文件的内容创建并打开文件接收数据写入文件关闭文件*///创建并打开文件int fd = open( filename, O_RDWR | O_CREAT | O_EXCL, 0666 );if( fd == -1 ){if( errno == EEXIST )  //文件已经存在,就直接打开即可{fd = open( filename, O_RDWR | O_TRUNC );}else {perror("open file error ");return -1;}}int write_size = 0;      //已经写入的字节数while( write_size < file_size ){//先接收数据 char buf[128] = {0};re = recv( sock_fd, buf, 100, 0 );if( re > 0 ){//写入文件 write( fd, buf, re );write_size += re;}else {perror("recv file error ");break;}}if( write_size == file_size ){printf("recv file success\n");}else {printf("recv file failed \n");}//关闭文件 close( fd );}int main( int argc, char *argv[] ){//1.创建套接字 int server_fd = socket( AF_INET, SOCK_STREAM, 0 );if( server_fd == -1 ){perror("socket server error ");return -1;}printf("server_fd = %d\n", server_fd );//2.绑定 服务器的ip和端口struct sockaddr_in  server_addr;server_addr.sin_family = AF_INET;                   //协议族 server_addr.sin_port = htons( atoi(argv[2]) );    //端口号inet_aton( argv[1], &server_addr.sin_addr );     //IP地址//设置端口号重用int n = 1;setsockopt( server_fd, SOL_SOCKET, SO_REUSEPORT, &n, sizeof(n) );int re = bind( server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr) );if( re == -1 ){perror("bind server error ");close( server_fd );return -1;}printf("bind server success\n");//3.监听 re = listen( server_fd, 5 );if( re == -1 ){perror("listen server error ");close( server_fd ); return -1;}printf("listen server success\n");//4.接受连接 struct sockaddr_in  client_addr;socklen_t len = sizeof(client_addr);int client_fd = accept( server_fd, (struct sockaddr *)&client_addr, &len );if( client_fd == -1 ){perror("accept error ");close( server_fd );return -1;}printf("client_fd = %d\n", client_fd );printf("client_ip = %s\n", inet_ntoa(client_addr.sin_addr) );//5.通信 -->接收文件 recv_file( client_fd );//6.关闭套接字 close( server_fd );}file_tcp_client.c   客户端 发送文件  int send_file( int sock_fd, char * filename ){//发送文件名的长度大小 int name_len = strlen(filename);int re = send( sock_fd, &name_len, sizeof(name_len), 0 );if( re == -1 ){perror("send name_len error ");return -1;}printf("send name_len success , len = %d\n", name_len );//发送文件名 re = send( sock_fd, filename, name_len, 0 );if( re == -1 ){perror("send filename error ");return -1;}printf("send filename success , filename = %s\n", filename );//发送文件的大小struct stat  st;stat( filename, &st );  //获取文件属性-->文件大小 int file_size = st.st_size;re = send( sock_fd, &file_size, sizeof(file_size), 0 );if( re == -1 ){perror("send file_size error ");return -1;}printf("send file_size success , file_size = %d\n", file_size );/* 发送文件的内容 打开文件读取发送 关闭文件 *///打开文件int fd = open( filename, O_RDONLY );if( fd == -1 ){perror("open file error ");return -1;}int read_size = 0;      //已经读取到的字节数while( read_size < file_size ){//先读取文件内容 char buf[128] = {0};re = read( fd, buf, 100 );if( re > 0 ){//发送数据 send( sock_fd, buf, re, 0 );read_size += re;}else {perror("read file error ");break;}}if( read_size == file_size ){printf("send file success\n");}else {printf("send file failed \n");}//关闭文件 close( fd );}int main( int argc, char *argv[] ){//1.创建套接字 int client_fd = socket( AF_INET, SOCK_STREAM, 0 );if( client_fd == -1 ){perror("socket client error "); return -1;}printf("client_fd = %d\n", client_fd );//2.设置服务器的ip和端口struct sockaddr_in  server_addr;server_addr.sin_family = AF_INET;                   //协议族 server_addr.sin_port = htons( atoi(argv[2]) );    //端口号inet_aton( argv[1], &server_addr.sin_addr );     //IP地址//3.连接服务器 int re = connect( client_fd, (struct sockaddr *)&server_addr, sizeof(server_addr) );if( re == -1 ){perror("connect error ");close( client_fd );return -1;}printf("connect success\n");//4.通信 --> 发送文件 send_file( client_fd, argv[3] );//5.关闭套接字close( client_fd );}

http://www.lryc.cn/news/412740.html

相关文章:

  • 口袋奇兵:游戏辅助教程!陆军搭配阵容推荐,平民必备!
  • Spring Boot 集成参数效验 Validator
  • 63、ELK安装和部署
  • 【Dash】简单的直方图
  • 【CTF-Crypto】格密码基础(例题较多,非常适合入门!)
  • Java对象流
  • 问界M7是不是换壳东风ix7? 这下有答案了
  • mybatis多条件in查询拓展
  • <Rust><iced>基于rust使用iced构建GUI实例:一个CRC16校验码生成工具
  • 动态规划与0/1背包问题:深入解析
  • Python爬虫:下载人生格言
  • 使用注意力机制的seq2seq
  • 我们的前端开发逆天了!1 小时搞定了新网站,还跟我说 “不要钱”
  • .NET 相关概念
  • Kubernetes 从集群中移除一个节点(Node)
  • 高德地图离线版 使用高德地图api的方法
  • springboot 集成私有化Ollama大模型开源框架,搭建AI智能平台
  • 6.key的层级结构
  • LogonTracer图形化事件分析工具
  • 【云原生】Prometheus监控Docker指标并接入Grafana
  • 搭建日志系统ELK(二)
  • 常用排序算法的实现与介绍
  • 仓颉语言 -- 宏
  • Nginx代理minIO图片路径实现公网图片访问
  • 从零开始掌握tcpdump:参数详解
  • 漏洞挖掘 | edusrc记一次某中学小程序渗透测试
  • vulhub:nginx解析漏洞CVE-2013-4547
  • 备战秋招:2024游戏开发入行与跳槽面试详解
  • 红外热成像手持终端:从建筑检测到野外搜救的全方位应用
  • day07 项目启动以及git