苏嵌实训——day17

news2024/9/26 1:22:24

文章目录

    • 1.1 信号灯集函数接口
      • 1.semget
      • 2.semctl
      • 3.封装初始化函数
      • 4. semop
  • 二 网络编程
    • 2.1 为什么要学习网络编程
    • 2.2 发展
      • 2.2.1 ARPnet
      • 2.2.2 TCP/IP协议
    • 2.3 网络体系结构以及OSI开放系统互联模型
    • 2.4 TCP/IP协议族
    • 2.5 五层模型
      • 2.6 TCP和UDP的异同点
    • 2.7 函数讲解
      • 2.7.1 socket
      • 2.7.2 bind()
      • 2.7.3 listen
      • 2.7.4 accept
      • 2.7.5 connect
    • 2.8 TCP服务器
    • 2.9 TCP客户端
    • 2.10 TCP并发服务器
    • 2.11 UDP 网络编程
      • 函数接口recvfrom/sendto

一 IPC通信之 信号灯集
信号灯集:是在内核空间的信号灯的集合

在这里插入图片描述

1.1 信号灯集函数接口

1.semget

头文件:#include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>

原型:int semget(key_t key, int nsems, int semflg);
功能:创建或者打开一个信号灯集
参数:
    key:信号灯集的秘钥(和共享内存,消息队列类似)
    nsems:创建的信号灯集中存在几个信号灯
    semflg:打开的方式
        IPC_CREAT:如果共享内存存在,则打开,不存在则创建
        例如:IPC_CREAT | 0664
        IPC_EXCL:如果存在则报错返回,如果不存在配合IPC_CREAT创建
返回值:
    成功返回一个信号灯集的ID
    失败返回-1

2.semctl

头文件:#include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>

       

原型:int semctl(int semid, int semnum, int cmd, ...);
功能:控制信号灯集
参数:
    semid:要控制的信号灯集的ID号
    semnum:信号灯的编号
    cmd:控制方式
        IPC_RMID:删除信号灯集,不考虑第二个参数
        GETVAL:获取信号灯的值
        SETVAL:设置信号灯的值
    ..:可变参数:是一个联合体
        union semun {
               int              val;    /* Value for SETVAL */
               struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
               unsigned short  *array;  /* Array for GETALL, SETALL */
               struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                           (Linux-specific) */
           };          
返回值:
    成功返回 0
    GETVAL:返回一个信号灯的值
    失败返回-1

3.封装初始化函数

int sem_init_val(int semid,int semnum,int val)
{
    union semun myval;  //需要自己定义
    myval.val = val;
    if(-1 ==semctl(semid,semnum,SETVAL,myval))
    {
        printf("初始化信号灯%d失败\n",semnum);
        return -1;   
    }
    return 0;
}

4. semop

头文件:#include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>

       

原型:int semop(int semid, struct sembuf *sops, size_t nsops);
功能:操作方式
参数:
semid:信号灯集的ID号
sops:操作方法结构体的地址
    unsigned short sem_num;  /* semaphore number */
    short          sem_op;   /* semaphore operation */
    short          sem_flg;  /* operation flags */
    使用案例:
         struct sembuf sops[2];
           int semid;

           /* Code to set semid omitted */

           sops[0].sem_num = 0;        /* Operate on semaphore 0 */
           sops[0].sem_op = 0;         /* Wait for value to equal 0 */
           sops[0].sem_flg = 0;

           sops[1].sem_num = 0;        /* Operate on semaphore 0 */
           sops[1].sem_op = 1;         /* Increment value by one */
           sops[1].sem_flg = 0;

           if (semop(semid, sops, 2) == -1) {
               perror("semop");
               exit(EXIT_FAILURE);
           }

nsops:同时操作的个数
    如果说同时操作很多信号灯,填写一个结构体数组                                    
返回值:
    成功返回0
    失败返回-1

//write

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
union semun {
    int  val;    /* Value for SETVAL */
};
int sem_init_val(int semid,int semnum,int val)
{
    union semun myval;  //需要自己定义
    myval.val = val;
    if(-1 ==semctl(semid,semnum,SETVAL,myval))
    {
        printf("初始化信号灯%d失败\n",semnum);
        return -1;   
    }
    return 0;
}
int sem_p(int semid,int semnum) //参数1:信号灯集  2.信号灯的编号
{   
    struct sembuf mybuf;
    mybuf.sem_num = semnum;        /* Operate on semaphore 0 */
    mybuf.sem_op = -1;         /* Wait for value to equal 0 */
    mybuf.sem_flg = 0;
    if(-1 == semop(semid,&mybuf,1))
    {
        printf("p操作失败\n");
        return -1;
    }
    return 0;
}
int sem_v(int semid,int semnum) //参数1:信号灯集  2.信号灯的编号
{   
    struct sembuf mybuf;
    mybuf.sem_num = semnum;        /* Operate on semaphore 0 */
    mybuf.sem_op = 1;         /* Wait for value to equal 0 */
    mybuf.sem_flg = 0;
    if(-1 == semop(semid,&mybuf,1))
    {
        printf("v操作失败\n");
        return -1;
    }
    return 0;
}
int main(int argc, char const *argv[])
{
    //生成一个共享内存使用的key值
    key_t mykey1 = ftok("/home/jsetc/jsetc/208/",'a');
    if(-1 == mykey1)
    {
        perror("生成键值失败");
        return -1;
    }
    //生成一个自定义key值
    key_t mykey = ftok("/home/jsetc/jsetc/208/day17/",'a');
    if(-1 == mykey)
    {
        perror("ftok");
        return -1;
    }
    //创建信号灯集
    int semid = semget(mykey,2,IPC_CREAT | 0664);
    if(-1 == semid)
    {
        perror("semget");
        return -1;
    }
    //初始化信号灯集
    sem_init_val(semid,0,1);
    sem_init_val(semid,1,0);


    //创建共享内存
    int shmid = shmget(mykey1,4096,IPC_CREAT | 0664);
    if(-1 == shmid)
    {
        perror("shmget");
        return -1;
    }
    printf("创建或者打开共享内存成功\n");
    //地址映射
    char *buf = (char *)shmat(shmid,NULL,0);
    if((char *)-1 == buf)
    {
        perror("shmat");
        return -1;
    }
    while(1)
    {
        sem_p(semid,0);    //p操作
        printf("请输入\n");
        scanf("%s",buf);
        sem_v(semid,1);
    }
    
    return 0;
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
union semun {
    int  val;    /* Value for SETVAL */
};
int sem_init_val(int semid,int semnum,int val)
{
    union semun myval;  //需要自己定义
    myval.val = val;
    if(-1 ==semctl(semid,semnum,SETVAL,myval))
    {
        printf("初始化信号灯%d失败\n",semnum);
        return -1;   
    }
    return 0;
}
int sem_p(int semid,int semnum) //参数1:信号灯集  2.信号灯的编号
{   
    struct sembuf mybuf;
    mybuf.sem_num = semnum;        /* Operate on semaphore 0 */
    mybuf.sem_op = -1;         /* Wait for value to equal 0 */
    mybuf.sem_flg = 0;
    if(-1 == semop(semid,&mybuf,1))
    {
        printf("p操作失败\n");
        return -1;
    }
    return 0;
}
int sem_v(int semid,int semnum) //参数1:信号灯集  2.信号灯的编号
{   
    struct sembuf mybuf;
    mybuf.sem_num = semnum;        /* Operate on semaphore 0 */
    mybuf.sem_op = 1;         /* Wait for value to equal 0 */
    mybuf.sem_flg = 0;
    if(-1 == semop(semid,&mybuf,1))
    {
        printf("v操作失败\n");
        return -1;
    }
    return 0;
}
int main(int argc, char const *argv[])
{
    //生成一个共享内存使用的key值
    key_t mykey1 = ftok("/home/jsetc/jsetc/208/",'a');
    if(-1 == mykey1)
    {
        perror("生成键值失败");
        return -1;
    }
    //生成一个自定义key值
    key_t mykey = ftok("/home/jsetc/jsetc/208/day17/",'a');
    if(-1 == mykey)
    {
        perror("ftok");
        return -1;
    }
    //创建信号灯集
    int semid = semget(mykey,2,IPC_CREAT | 0664);
    if(-1 == semid)
    {
        perror("semget");
        return -1;
    }
    //初始化信号灯集
    sem_init_val(semid,0,1);
    sem_init_val(semid,1,0);


    //创建共享内存
    int shmid = shmget(mykey1,4096,IPC_CREAT | 0664);
    if(-1 == shmid)
    {
        perror("shmget");
        return -1;
    }
    printf("创建或者打开共享内存成功\n");
    //地址映射
    char *buf = (char *)shmat(shmid,NULL,0);
    if((char *)-1 == buf)
    {
        perror("shmat");
        return -1;
    }
    while(1)
    {
        sem_p(semid,1);    //p操作
        printf("buf = %s\n",buf);
        sem_v(semid,0);
    }    
    return 0;
}

二 网络编程

2.1 为什么要学习网络编程

网络编程就是最后一种进程间通信的方式-----》套接字通信
套接字通信:前六种进程间通信只能实现同一台主机的多个进程通信,但是套接字通信可以实现不同主机的多个进程间通信。

2.2 发展

Arpanet
TCP/IP协议:一共两个协议
网络体系结构:发明了osi开放系统互联模型
TCP/IP协议族:有很多个协议组成

2.2.1 ARPnet

是网络的最早雏形
不能互联不同类型的计算机和不同类型的操作系统,没有纠错功能。

2.2.2 TCP/IP协议

TCP/IP协议分成了两个不同的协议:
用来检测网络传输中差错的传输协议:TCP
专门分则对不同网络进行互联的互联网协议:IP

2.3 网络体系结构以及OSI开放系统互联模型

OSI(国际标准化组织)提供的一个网络体系结构
OSI因为层次结构比较复杂,所以到目前也没有使用,但是他是最早提出的网络体系结构
OSI七层模型:
应用层: 面向用户的,应用程序
表示层:对数据进行加密和解密
会话层:建立逻辑名字和物理名字之间的关系
运输层:用于控制数据的有效传输
网络层:数据分组,路由选择
数据链路层:将数据组成发送或者接收的帧数据
物理层:选择物理介质
注意:每个层次之间的顺序是不能改变的

2.4 TCP/IP协议族

后期基于OSI发明了TCP/IP协议族,这个协议族由很多协议组成:
TCP/IP协议族一共四层:
应用层:telnet,www,FTP,TFTP,SIP
传输层:tcp udp
网络层:IP,ICMP
网络接口与物理层:网卡驱动,物理接口

2.5 五层模型

应用层:
传输层:
网络层:
数据链路层:
物理层:

2.6 TCP和UDP的异同点

相同点:
    同为传输协议
不同点:
    TCP是面向连接的,可靠的,基于字节流的传输协议
    UDP是面向无连接,不可靠的,基于数据报的传输协议
Tcp的概念
    是一种面向链接的传输协议,它能提供高可靠性的通信(即数据无误,数据不丢失,数据无失序,数据无重复的到达),TCP有回传机制
    使用情况:
        适合对于传输质量要求较高,以及传输大量数据的通信,比图MSN/QQ登录,账号管理时需要使用TCP协议
UDP的概念
    是不可靠的,无连接的传输协议,在数据发送前,因为不需要进行链接,所以可以高效率的数据传输
    使用情况:
        适用于对于实时性要求较高的场景,比如:流媒体

2.7 函数讲解

2.7.1 socket

头文件:#include <sys/types.h>          /* See NOTES */
       #include <sys/socket.h>

原型:int socket(int domain, int type, int protocol);
功能:创建套接字,返回一个文件描述符
参数:
    domain:通信域
       AF_UNIX, AF_LOCAL   Local communication              unix(7)   //本地通信
       AF_INET             IPv4 Internet protocols          ip(7)    //ipv4网络协议
       AF_INET6            IPv6 Internet protocols          ipv6(7)   //ipv6网络协议
       AF_IPX              IPX - Novell protocols
       AF_NETLINK          Kernel user interface device     netlink(7)
       AF_X25              ITU-T X.25 / ISO-8208 protocol   x25(7)
       AF_AX25             Amateur radio AX.25 protocol
       AF_ATMPVC           Access to raw ATM PVCs
       AF_APPLETALK        AppleTalk                        ddp(7)
       AF_PACKET           Low level packet interface       packet(7)   //底层协议通信
       AF_ALG              Interface to kernel crypto API
    type:套接字类型
       SOCK_STREAM   :流式套接字   --->tcp  

       SOCK_DGRAM   : 数据报套接字 --->udp
       SOCK_RAW :      原始套接字
    protocol:附加协议,传0表示不需要其他协议
返回值:
    成功:文件描述符
    失败: -1

2.7.2 bind()

头文件:#include <sys/types.h>          /* See NOTES */
       #include <sys/socket.h>

原型:int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
功能:将套接字与网络信息结构体绑定
参数:
    sockfd:文件描述符,socket的返回值
    addr:网络信息结构体
    通用结构体:一般不用
        struct sockaddr {
               sa_family_t sa_family;
               char        sa_data[14];
           }
    网络信息结构体:                                 
        stuct sockaddr_in{
            sa_family_t sin_family;   //地址族:AF_INET
            in_port_t  sin_port;    //网络字节序的端口号
            struct in_addr sin_addr  //ip地址   
                ---》struct in_addr
                    {
                        uint32_t s_addr;    //网络字节序的无符号4字节整数Ip地址                    
                    }                                  
        }
        addrlen:addr的大小
返回值:
    成功:返回0
    失败:返回-1

2.7.3 listen

头文件:#include <sys/types.h>          /* See NOTES */
       #include <sys/socket.h>

       
原型:int listen(int sockfd, int backlog);
功能:将套接字设置为被动监听状态
参数:
    sockfd:文件描述符,socket的返回值
    backlog:允许同时连接的客户端的个数,一般设置为5,10
返回值:
成功:0
失败:-1

2.7.4 accept

头文件:#include <sys/types.h>          /* See NOTES */
       #include <sys/socket.h>

       
      
原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:阻塞等待客户端的连接
参数:
    sockfd:文件描述符,socket的返回值
    addr:被填充的网络信息结构体,如果由客户端连接服务器,服务器可以通过这个参数获取客户端的信息
    addrlen:addr的大小
返回值:
成功:返回文件描述符
失败:-1

2.7.5 connect

头文件:#include <sys/types.h>          /* See NOTES */
       #include <sys/socket.h>

       
      
原型:int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);

功能:给服务器发送连接请求
参数:
    sockfd:文件描述符,socket的返回值
    addr:要连接的服务器的网络信息结构体,需要客户端自己填充
    addrlen:addr的大小
返回值:
成功:返回0
失败:-1

2.8 TCP服务器

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include<arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int main(int argc, char const *argv[])
{
    //创建套接字
    int sockfd = socket(AF_INET,SOCK_STREAM,0);  //IPV4协议,流式套接字,具体的协议类型
    if(-1 == sockfd)
    {
        perror("socket");
        return -1;
    }
    struct sockaddr_in server_addr;   //保存服务器的信息
    memset(&server_addr,0,sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8000);
    server_addr.sin_addr.s_addr = inet_addr("192.168.98.147");
    //绑定信息
    int ret = bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr));
    if(-1 == ret)
    {
        perror("bind");
        return -1;
    }


    //设置监听队列
    ret = listen(sockfd,10);
    if(-1 == ret)
    {
        perror("listen");
        return -1;
    }
    printf("等待客户端进行连接...、\n");
    struct sockaddr_in Client_addr;    //用于保存客户端的信息
    int length = sizeof(Client_addr);
    int fd = accept(sockfd,(struct sockaddr *)&Client_addr,&length);
    if(-1 == fd)
    {
        perror("accept");
        return -1;
    }
    printf("接收客户端的连接 %d\n",fd);
    char buf[32] = {0};
    while(1)
    {
        ret = recv(fd,buf,sizeof(buf),0);
        if(-1 == ret)
        {
            perror("recv");
            return -1;
        }
        if(strcmp(buf,"bye") == 0)
        {
            break;
        }
        printf("%s\n",buf);
        memset(buf,0 ,sizeof(buf));
    }
    close(fd);
    close(sockfd); 
    return 0;
}

2.9 TCP客户端

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include<arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>


int main(int argc, char const *argv[])
{
    //创建套接字
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(sockfd == -1)
    {
        perror("socket");
        return -1;
    }
    //向服务器发起连接
    struct sockaddr_in server_addr;   //保存服务器的信息
    memset(&server_addr,0,sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8000);
    server_addr.sin_addr.s_addr = inet_addr("192.168.98.147");
    int ret = connect(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr));
    if(-1 == ret)
    {
        perror("connect");
        return -1;
    }
    char buf[32] = {0};
    while(1)
    {
        scanf("%s",buf);
        ret = send(sockfd,buf,strlen(buf),0);
        if(-1 == ret)
        {
            perror("send");
            return -1;
        }
        if(strcmp(buf,"bye") == 0)
        {
            break;
        }
        memset(buf,0,sizeof(buf));
    }
    close(sockfd);
    return 0;
}

2.10 TCP并发服务器

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include<arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <pthread.h>
void * ClientHandler(void *arg)
{
    int ret;
    int fd = *(int *)arg;
    char buf[32] = {0};
    pthread_detach(pthread_self());    //线程结束,自动释放资源
    while(1)
    {
        ret = recv(fd,buf,sizeof(buf),0);
        if(-1 == ret)
        {
            perror("recv");
            return (void *)-1;
        }
        else if(0 == ret)
        {
            break;   //客户端异常退出
        }
        if(strcmp(buf,"bye") == 0)
        {
            break;
        }
        printf("接收%d客户端 %s\n",fd,buf);
        memset(buf,0 ,sizeof(buf));
    }
    printf("%d 客户端退出!\n",fd);
    close(fd);
}
int main(int argc, char const *argv[])
{
    //创建套接字
    int sockfd = socket(AF_INET,SOCK_STREAM,0);  //IPV4协议,流式套接字,具体的协议类型
    if(-1 == sockfd)
    {
        perror("socket");
        return -1;
    }
    struct sockaddr_in server_addr;   //保存服务器的信息
    memset(&server_addr,0,sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8000);
    server_addr.sin_addr.s_addr = inet_addr("192.168.98.147");
    //绑定信息
    int ret = bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr));
    if(-1 == ret)
    {
        perror("bind");
        return -1;
    }


    //设置监听队列
    ret = listen(sockfd,10);
    if(-1 == ret)
    {
        perror("listen");
        return -1;
    }
    printf("等待客户端进行连接...、\n");
    struct sockaddr_in Client_addr;    //用于保存客户端的信息
    int length = sizeof(Client_addr);
    
    while(1)
    {
        int fd = accept(sockfd,(struct sockaddr *)&Client_addr,&length);
        if(-1 == fd)
        {
            perror("accept");
            return -1;
        }
        printf("接收客户端的连接 %d\n",fd);
        //为每一个客户端创建新的线程
        pthread_t tid;
        ret = pthread_create(&tid,NULL,ClientHandler,&fd);
        if(ret != 0)
        {
            perror("pthread_create");
            return -1;
        }
    }
    close(sockfd); 
    return 0;
}
#!/bin/bash

for ((i=0;i<100;i++))
do
    ./4-Tcp客户端 &
    sleep 0.1
done

练习:实现客户端下载服务器所在目录文件
客户端发送要下载的文件名给服务器
服务器判断文件是否存在,将结果告知客户端
如果文件存在,服务器读取文件内容,并发送给客户端
客户端收到文件内容并写入指定的文件

2.11 UDP 网络编程

服务器:
	创建套接字 socket
	填充服务器网络信息结构体
	将套接字和网络信息结构体绑定bind
	进行通信 recvfrom /sendto()
客户端:
	创建套接字 socket
	填充网络信息结构体
	进行通信 recvfrom/sendto

函数接口recvfrom/sendto

------recvfrom

1.recvfrom/sendto
------recvfrom
头文件:#include <sys/types.h>
       #include <sys/socket.h>
原型:ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);
功能:接收数据
参数:
    前四个和recv一样
    src_addr:源的地址,接收谁的数据,他的信息会自动填充到这个参数
    addrlen:src_addr的大小
返回值
    成功:实际接收的字节数
    失败: 返回-1
------sendto
头文件:#include <sys/types.h>
       #include <sys/socket.h>
原型:ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                      const struct sockaddr *dest_addr, socklen_t addrlen);

功能:接收数据
参数:
    前四个和send一样
    dest_addr:目的地址,需要自己指定
    addrlen:dest_addr的大小
返回值
    成功:发送的字节数
    失败: 返回-1

//udp服务器

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#define ERRLOG(errmsg) do{\
                            perror(errmsg);\
                            printf("%s - %s - %d\n",__FILE__,__func__,__LINE__);\
                            exit(1);\
                            }while(0)
int main(int argc, char const *argv[])
{
    int sockfd;
    //第一步:创建套接字
    if(-1 == (sockfd = socket(AF_INET,SOCK_DGRAM,0)))
    {
        ERRLOG("socket error");
    }
    
    struct sockaddr_in serveraddr,clientaddr;
    socklen_t addrlen = sizeof(serveraddr);


    //第二步:填充服务器网络信息结构体  
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr("192.168.98.147");
    serveraddr.sin_port = 8888;


    //第三步:将套接字与服务器网路信息结构体绑定
    int ret = bind(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
    if(ret == -1)
    {
        ERRLOG("bind");
    }
    //进行通信
    char buf[32] = {0};
    while(1)
    {
NEXT:
        if(recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&clientaddr,&addrlen) == -1)
        {
            ERRLOG("recvfrom");
        }
        if(strcmp(buf,"bye") == 0)
        {
            printf("客户端%s-%d退出了\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
            goto NEXT;
        }
        printf("%s-%d: %s\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port),buf);
    }
    return 0;
}

//udp客户端

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#define ERRLOG(errmsg) do{\
                            perror(errmsg);\
                            printf("%s - %s - %d\n",__FILE__,__func__,__LINE__);\
                            exit(1);\
                            }while(0)
int main(int argc, char const *argv[])
{
    int sockfd;
    //第一步:创建套接字
    if(-1 == (sockfd = socket(AF_INET,SOCK_DGRAM,0)))
    {
        ERRLOG("socket error");
    }
    
    struct sockaddr_in serveraddr,clientaddr;
    socklen_t addrlen = sizeof(serveraddr);


    //第二步:填充服务器网络信息结构体  
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr("192.168.98.147");
    serveraddr.sin_port = 8888;


    //进行通信
    char buf[32] = {0};
    while(1)
    {
        scanf("%s",buf);
        if(sendto(sockfd,buf,32,0,(struct sockaddr *)&serveraddr,addrlen) == -1)
        {
            ERRLOG("sendto");
        }
        if(strcmp(buf,"bye") == 0)
        {
            printf("客户端退出了\n");
        }
        memset(buf,0,sizeof(buf));
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/187195.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

k8s快速入门、集群部署-62

一&#xff1a;k8s简介 Kubernetes 简称 k8s。是用于自动部署&#xff0c;扩展和管理容器化应用程序的开源系统。 1.1 官方文档 中文官网&#xff1a;https://kubernetes.io/zh/ 中文社区&#xff1a;https://www.kubernetes.org.cn/ 官方文档&#xff1a;https://kubernete…

利用钉钉机器人Webhook向钉钉群推送告警通知

一、配置钉钉群 1、新建一个接收通知的钉钉群 如下图&#xff0c;创建一个接收通知的钉钉群 选择项目群&#xff0c;点创建 输入群名称&#xff0c;右侧选择群成员&#xff0c;最后点击右下角的创建 2、对群进行设置 点群右上角的设置按钮 点击 “智能群助手” 点 “添加机器人…

常见测试案例汇总

作者&#xff1a;~小明学编程 文章专栏&#xff1a;测试开发 格言&#xff1a;热爱编程的&#xff0c;终将被编程所厚爱。 目录 水杯的测试用例 功能性测试 界面测试 性能测试 兼容性测试 易用性测试 安全测试 电梯的测试用例 界面测试 功能测试 性能测试 兼容性…

明明加了唯一索引,为什么还是产生重复数据?

距离上次发稿 已经过去好久了&#xff0c; 开搞&#xff0c;2023第一稿&#xff1b; .还原问题现场 前段时间&#xff0c;为了防止商品组产生重复的数据&#xff0c;我专门加了一张防重表。 问题就出在商品组的防重表上。 具体表结构如下&#xff1a; 为了保证数据的唯一性&a…

《吴军数学通识讲义》读后感

先抛一个问题&#xff0c;一副扑克牌随机发牌&#xff0c;均匀发给三人&#xff0c;已知你手上有两张K&#xff0c;另外两张K&#xff0c;每人一张的概率大&#xff0c;还是分给一个人的概率大&#xff0c;或者这两种场景概率一样&#xff1f; 从小开始学数学&#xff0c;但毕业…

PostgreSQL实战之物理复制和逻辑复制(六)

目录 PostgreSQL实战之物理复制和逻辑复制&#xff08;六&#xff09; 6 延迟备库 6.1 延迟备库的意义 6.2 延迟备库部署 6.3 recovery_min_apply_delay参数对同步复制的影响 PostgreSQL实战之物理复制和逻辑复制&#xff08;六&#xff09; 6 延迟备库 延迟备库是指可以配…

Flink官方例子解析:Flink源码子项目flink-examples

1. 简介 很多朋友在学习Flink的时候都希望能有个demo代码来参考实践&#xff0c;于是在百度或者Google一顿搜索&#xff0c;虽然能找到很多demo代码&#xff0c;但是这些demo要么版本比较旧&#xff0c;要么代码不全&#xff0c;根本跑不通。 其实&#xff0c;Flink官网就提供…

10、矩阵分析

目录 一、向量和矩阵的范数运算 二、矩阵的秩 三、矩阵的行列式 四、矩阵的迹 五、矩阵的化零矩阵 六、矩阵的正交空间 七、矩阵的约化行阶梯形式 八、矩阵空间之间的夹角 MATLAB 提供的矩阵分析函数&#xff1a; 一、向量和矩阵的范数运算 (1)在MATLAB中&#xff0c;…

不平衡数据集的建模的技巧和策略

不平衡数据集是指一个类中的示例数量与另一类中的示例数量显著不同的情况。 例如在一个二元分类问题中&#xff0c;一个类只占总样本的一小部分&#xff0c;这被称为不平衡数据集。类不平衡会在构建机器学习模型时导致很多问题。 不平衡数据集的主要问题之一是模型可能会偏向多…

笔记本怎么录制屏幕?笔记本录屏有这一款就够了

为了携带方便&#xff0c;很多小伙伴都选择笔记本电脑作为自己学习和办公的工具。在使用笔记本时&#xff0c;我们有时需要对它进行屏幕录制&#xff0c;那你知道笔记本怎么录制屏幕吗&#xff1f;怎样才能又快又好地录制屏幕&#xff1f;今天小编就给大家带来一款能高效录制笔…

DBCO-SS-NH2,二苯并环辛炔-二硫键-氨基,DBCO-SS-amine

DBCO-SS-NH2,二苯并环辛炔-二硫键-氨基&#xff0c;DBCO-SS-amine 英文名称&#xff1a;DBCO-SS-NH2、DBCO-SS-amine 中文名称&#xff1a;二苯并环辛炔-二硫键-氨基 外 观: 浅黄色或白色固体 分子式: C23H25N3O2S2 分子量: 439.59 存储环境:尽可能储存在-20℃环境下&…

网络原理(TCP/IP)(5)

2.IP协议的核心功能:能够在两点之间规划出来一条合适的路径 1)地址管理&#xff1a;通过一系列的规则&#xff0c;可以把网络上设备的地址给描述出来 2)路由地址&#xff1a;根据当下的源IP和目的地址&#xff0c;规划成一条合适的路径&#xff0c;啥叫合适&#xff1f;关键是看…

【IoT】项目管理:做好敏捷管理,从敏捷看板开始

随着移动互联网、软件即服务&#xff08;SaaS&#xff09;和基于云计算的快速发展&#xff0c;你需要加快你的产品开发周期&#xff0c;将重点工作放在定义核心功能集的前端。 你可以从敏捷软件开发思想中借鉴一些最佳实践&#xff0c;并将这些实践应用于团队管理中。 敏捷思想…

React+eggjs+mysql实现多文件上传

文章目录一、开发环境二、数据库准备files表【视项目需求不同可略过&#xff0c;一般小项目可忽略】1.数据库准备files表的目的2.表结构三、后端接口准备1.配置config2.router.ts中配置路由3.创建controller4.创建service①为什么做这步②创建service/common文件③service/comm…

IronWebScraper for .NET 2023.1 Crack

用于从 HTML Web 应用程序中提取干净的结构化数据的 C# 框架。 IronWebScraper for .NET 2023 &#xff1a;Adds support for Microsoft .NET 6 and .NET 7.January 27, 2023 - 17:25 New Version &#xff1a;&#xff1a;&#xff1a; Added support for Microsoft .NET 6 an…

【Java】SpringCloud使用

SpringCloud使用 发起远程调用 根据订单id查询订单的同时&#xff0c;把订单所属的用户信息一起返回&#xff0c;但订单信息和用户信息分属两个不同的模块。 本质上是订单模块向用户模块发起请求&#xff0c;在spring中使用resttemplate发起。 MapperScan("cn.itcast.o…

电脑配置怎么看?这3种方法就可以轻松查看

在我们的日常生活和工作中&#xff0c;我们越来越离不开计算机。对于一台好的电脑&#xff0c;首先&#xff0c;我们需要了解它的配置&#xff0c;以便更好地选择它。电脑配置怎么看&#xff1f;可能还有很多人不知道。别担心&#xff0c;本篇文章就是来教会你如何查看电脑的配…

Android studio集成flutter

1.获取Flutter SDK 视窗安装|扑动 (flutter.dev) 2.配置环境变量 3.Android Studio安装Flutter插件 4.打开管理窗口cmd&#xff0c;输入flutter doctor。 5.因为第二步是感叹号&#xff08;如下图&#xff09;&#xff0c;需要run: flutter doctor --android-licenses&#xf…

基础课程7:多线程与Pad可获得性

目标 GStreamer自动处理多线程&#xff0c;但在某些情况下&#xff0c;您可能需要手动解耦线程。本教程展示了如何做到这一点&#xff0c;此外&#xff0c;还完成了关于Pad可用性的阐述。更准确地说&#xff0c;本文档解释了: 如何为管道的某些部分创建新的执行线程Pad的可用…

SpringCloud之消息总线

spring CloudBus 将分布式的节点和轻量的消息代理连接起来。这可以用于广播配置文件的更改或者其他的管理工作。一个关键的思想就是&#xff0c;消息总线可以为微服务做监控&#xff0c;也可以作为应用程序之间相互通讯。 一、准备工作 本文还是基于上一篇文章来实现。按照官…