输入参数

  1. int main(int argc,char **argv);
  2. argc代表输入参数个数+1
  3. argv代表输入参数数组
  4. argv[0]代表当前可执行文件的名称
  5. argv[1]代表第一个输入参数

标准IO

用于读写普通文件

  1. //打开文件
  2. FILE *fopen(const char *pathname, const char *type)
  3. //临时文件
  4. FILE *tmpfile(void)
  5. //格式化输出
  6. int fprintf(FILE *fp, const char *format, ...)
  7. //格式化输出到缓冲区
  8. int sprintf(char *buf, const char *format, ...)
  9. //读文件
  10. size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
  11. //从指定流中读一行
  12. char *fgets(char *str, int n, FILE *stream)
  13. //文件位置偏移
  14. int fseek(FILE *stream, long int offset, int whence)
  15. //写文件
  16. size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
  17. //关闭文件
  18. int fclose(FILE *stream)
  19. //常用流
  20. stdin 标准终端输入流
  21. stdout 标准终端输出流
  22. #include <stdio.h>
  23. #include <errno.h>
  24. #define N 64
  25. int main(int argc,const char *argv[])
  26. {
  27. FILE *fps,*fpd;
  28. int n;
  29. char buf[N];
  30. if (argc < 3) {
  31. printf("Usage:%s <src_file> <dst_file>\n",argv[0]);
  32. return -1;
  33. }
  34. /*打开源文件和目标文件*/
  35. if ((fps = fopen(argv[1],"r")) == NULL) {
  36. perror("fopen");
  37. return -1;
  38. }
  39. if ((fpd = fopen(argv[2],"w+")) == NULL) {
  40. perror("fopen");
  41. return -1;
  42. }
  43. /*读写流*/
  44. while ((n = fread(buf,1,N,fps)) > 0) { /*当n接收到的字符数小于0时,表示已经读取到文件的末尾*/
  45. fwrite(buf,1,n,fpd);
  46. }
  47. fclose(fps);
  48. fclose(fpd);
  49. return 0;
  50. }

文件IO

用于读写设备文件、管道等

  1. //打开文件
  2. int fd=open(char *name,int how);
  3. /* name:设备路径和名称
  4. * how: 权限: O_RDONLY 只读
  5. * O_WRONLY 只写
  6. * O_CREAT 创建
  7. */
  8. //读文件
  9. read(int fd,const void *buf,size_t count);
  10. //写文件
  11. write(int fd,const void *buf,size_t count);
  12. //关闭文件
  13. close(int fd);

多进程

原型

pid_t fork( void);

返回值: 成功调用一次会有两个返回值, 子进程返回0, 父进程返回子进程ID; 出错返回-1
Note:

进程创建成功后,父进程以及子进程都从fork()之后开始执行,只是PID不同,fork语句可以看成讲程序切为A,B两个部分.(fock()成功之后,子进程克隆了父进程的所有变量,环境变量,程序计数器的当前空间和值)

结束进程

使用exit()函数 头文件 #include 使用_exit()函数 头文件 #include 区别: exit()结束进程会刷新缓冲区, _exit()不会

回收进程

用来回收资源处理僵尸进程

  1. 使用wait()函数回收进程

原型: pid_t wait(int *status) 成功返回子进程的进程号, 失败返回-1, wait()是阻塞直至某个子进程终止

  1. 使用waitpid()函数回收进程

原型: pid_t waitpid(pid_t pid, int *status, int options); 成功返回子进程的进程号,失败返回-1

僵尸进程

僵尸进程是父进程未结束, 但子进程结束了,但仍然保留一些信息等待父进程回收资源,但父进程没有使用wait/waitpid回收子进程资源导致的,当父进程结束后会回收僵尸进程资源。 使用这个信号signal(SIGCHLD,SIG_IGN); 父进程提前死亡,子进程会交给init进程,当子进程死亡后init进程会回收子进程资源避免成为僵尸进程

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. int main()
  4. {
  5. pid_t fpid;
  6. printf("hello fork\n");
  7. fpid = fork();
  8. if (fpid < 0)
  9. printf("error fork\n");
  10. else if (fpid == 0)
  11. printf("I am the child process, my pid is %d , my parent pid is%d\n",
  12. getpid() ,getppid());
  13. else
  14. printf("I am the parent process, my pid is %d\n",getpid());
  15. return 0;
  16. }
  17. /* result:
  18. * hello fork
  19. * I am the parent process, my pid is 3361
  20. * I am the child process, my pid is 3362 , my parent pid is 3361
  21. */
  22. //结果只看到一次hello fork, 因为子进程克隆了父进程的程序计数器,只执行fork()后的内容

进程通信

image.png

消息队列

接口

  1. //头文件
  2. #include <sys/types.h>
  3. #include <sys/ipc.h>
  4. #include <sys/msg.h>
  5. //创建/打开消息队列
  6. int msgget(key_t key,int flag);
  7. /* key: 和消息队列关联的key
  8. * flag: 访问权限
  9. * 返回值: 成功返回消息队列ID, 失败返回-1
  10. */
  11. //控制消息队列
  12. int msgctl(int msgqid,int cmd, struct msqid_ds *buf);
  13. /* msgqid: 消息队列id
  14. * cmd: IPC_STAT: 读取消息队列属性,结果保存在buf
  15. * IPC_SET: 设置消息队列属性
  16. * IPC_RMID: 删除消息队列
  17. */
  18. //添加一条消息到消息队列
  19. int msgsnd(int msgqid, const void *msgp,size_t size,int flag);
  20. /* msgid:消息队列id
  21. * msgp:指向消息的指针
  22. * struct msgbuf {
  23. * long mtype; //消息类型
  24. * char mtext[N]; //消息正文
  25. * };
  26. * size:消息正文的字节数
  27. * flag: IPC_NOWAIT: 非阻塞
  28. * 0: 阻塞
  29. */
  30. //从消息队列接收一条消息
  31. int msgrcv(int msgqid,void *msgp,size_t size,long msgtype,int flag);
  32. /* msgqid:消息队列id
  33. * msgq:接收消息缓冲区
  34. * size:要接收消息的字节数
  35. * msgtype: 0:接收消息队列中的第一个消息
  36. * 大于0: 接收消息队列中第一个类型为msgtype的消息
  37. * 小于0: 接收消息对垒中类型值不大于msgtype的绝对值且类型又最小的消息
  38. * flag: IPC_NOWAIT:非阻塞
  39. * 0:阻塞
  40. */

server

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <sys/types.h>
  5. #include <sys/msg.h>
  6. #include <signal.h>
  7. #include <string>
  8. struct msgbuf {
  9. long type; //消息类型
  10. char voltage[124]; //消息正文
  11. }
  12. int main(int argc, char **argv[])
  13. {
  14. int msgid,readret,key;
  15. struct msgbuf sendbuf;
  16. key = ftok(".",1);
  17. if (key < 0)
  18. {
  19. printf("create key fail\n");
  20. return -1;
  21. }
  22. msgid = msgget(key,IPC_CREAT|0777);
  23. if (msgid<0)
  24. {
  25. printf("create msg queue fail\n");
  26. return -1;
  27. }
  28. printf("create msg queue success, msgid=%d\n",msgid);
  29. system("ipcs -q");
  30. sendbuf.type = 100;
  31. while(1)
  32. {
  33. memset(sendbuf.voltage,0,124);
  34. printf("please input message:");
  35. fgets(sendbuf.voltage,124,stdin);
  36. msgsnd(msgid,(void *)&sendbuf,strlen(sendbuf.voltage),0);
  37. }
  38. return 0;
  39. }

client

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <signal.h>
#include <string.h>

struct msgbuf {
    long type;            //消息类型
    char voltage[124];    //消息正文
};

int main(int argc,char **argv[])
{
    int msgid,key;
    struct msgbuf readbuf;

    key = ftok(".",1);
    if (key<0)
    {
        printf("create key fail\n");
        return -1;
    }

    msgid = msgget(key,IPC_CREAT|0777);
    if(msgid<0)
    {
        printf("create msg queue fail\n");
        return -1;
    }
    printf("create msg queue success,msgid=%d\n",msgid);
    system("ipcs -q");

    while(1)
    {
        memset(readbuf.voltage,0,124);
        msgrcv(msgid,(void *)&readbuf,124,100,0);
    }
    return 0;
}

共享内存

image.png

共享内存没有同步和互斥机制, 使用时需要配合信号量来实现共享内存存取的同步

接口

/* 头文件 */
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/>

/* 生成Key */
key_t ftok(const char *pathname, int proj_id);
/* pathname: 指定的文件名,文件一定要存在
 * proj_id: 0~255,可以自行约定
 */

/* 创建共享内存 */
int shmget(key_t key,int size,int shmflg);
/* key: IPC_PRIVATE(用于子父进程)或ftok()的返回值
 * size: 共享内存区大小
 * shmflg: 权限位, 创建使用IPC_CREAT, 已存在使用IPC_EXCL
 * 返回值: 成功返回共享内存的ID, 失败返回-1
 */

/* 操作共享内存 */
int shmctl(int shm_id,int cmd,struct shmid_ds *buf);
/* shm_id: shmget返回的ID
 * cmd: IPC_STAT : 用共享内存的当前关联值覆盖shmid_ds的值
 *        IPC_SET: 共享内存的当前关联值设置为shmid_ds结构中给出的值
 *        IPC_RMID: 删除共享内存段
 * buf: 共享内存模式和访问权限的结构指针
 */

/* 将共享内存映射到用户空间 */
void *shmat(int shm_id,const void *shm_addr,int shmflg);
/* shm_id: shmget返回的ID
 * shm_addr: 指定共享内存连接到当前进程中的地址位置,通常为空,表示让系统来选择共享内存的地址
 * shmflg: 一组标志位,通常为0
 * 返回值: 返回映射后的内存地址
 */

/* 解除地址映射,该操作不删除标志符和数据结构 */
int shmdt(const void *shmaddr);
/* shmaddr: shmat返回的地址
 */

client

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <string.h>

typedef struct 
{
    int size;
    char content[0];
}shm_buf;


int main(int argc, char const *argv[])
{
    int shmid;
    int key;
    shm_buf *p;

    key = ftok("/",1);
    if (key<0){
        printf("create key fail\n");
        return -1;
    }
    printf("create key success key=0x%X\n",key);
    shmid = shmget(key,128,IPC_CREAT|0777);
    if(shmid<0){
        printf("create shared memory fail\n");
        return -1;
    }
    printf("create shared memory success ,shmid=%d\n",shmid);
    system("ipcs -m");
    p = (shm_buf *)shmat(shmid,NULL,0);
    if(p == NULL){
        printf("shmat fail\n");
        return -1;
    }
    printf("shmat success\n");
    while(1)
    {
        printf("input message: ");
        fgets(p->content,128,stdin);
        p->size = strlen(p->content);
        printf("share memory data:%s\n", p->content);
    }
    shmctl(shmid,IPC_RMID,NULL);
    return 0;
}

server

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <string.h>

typedef struct 
{
    int size;
    char content[0];
}shm_buf;

int main(int argc, char const *argv[])
{
    int shmid;
    int key;
    shm_buf *p;

    key = ftok("/",1);
    if (key<0){
        printf("create key fail\n");
        return -1;
    }
    printf("create key success key=0x%X\n",key);
    shmid = shmget(key,128,IPC_CREAT|0777);
    if(shmid<0){
        printf("create shared memory fail\n");
        return -1;
    }
    printf("create shared memory success ,shmid=%d\n",shmid);
    system("ipcs -m");
    p = (shm_buf *)shmat(shmid,NULL,0);
    if(p == NULL){
        printf("shmat fail\n");
        return -1;
    }
    while(1)
    {
        if (p->size>0){
            printf("shm buf:%s\n", p->content);
            p->size = 0;
        }
    }
    shmctl(shmid,IPC_RMID,NULL);
    return 0;
}

管道

无名管道

面向子父进程间的通信,实际上是一个单向队列, 在一端读,另一端写

           +----+-----+-----+
      fd[0]|    |     |     | fd[1]
read ----> |    |     |     | <---write
           +----+-----+-----+

/* 创建 */
#include <unistd.h>
int pipe(int fd[2]);
/* 管道文件描述符 fd[0]为读端, fd[1]为写端
 * 返回值0为成功,返回值1为失败
 */
/* 读 */
read(fd[0],readbuf,size);
/* 写 */
write(fd[1],writebuf,size);
/* 关闭 */
close(fd)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, int **argv[])
{
    int fd[2];
    pid_t fpid;
    int ret = 0;
    char write_buf[] = "hello pipe";
    char read_buf[128] = {0};
    ret = pipe(fd);
    if (ret < 0)
    {
        printf("pipe error\n");
        return -1;
    }
    printf("create pipe sucess fd[0]=%d,fd[1]=%d\n",fd[0],fd[1]);
    fpid = fork();
    if (fpid < 0)
    {
        printf("error fork\n");
    }
    else if (fpid == 0)
    {
        read(fd[0],read_buf,sizeof(read_buf));
        printf("read_buf=%s\n",read_buf);
        close(fd[0]);
    }
    else
    {
        write(fd[1],write_buf,sizeof(write_buf));
        close(fd[1]);
    }

    return 0;
}

有名管道

可用于任何进程间通信, 在内核上表现为一个文件, 进程通过文件IO操作读写信息 int mkfifo(const char *filename, mode_t mode ); 成功返回0, 失败返回-1

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc,char **argv[])
{
    int ret,fd;
    char write_buf[] = "hello pipe";

    if (access("./testPipe",0)<0)
    {
        ret = mkfifo("./testPipe",0777);
        if(ret<0)
        {
            printf("create pipe fail\n");
            return -1;
        }
    }
    fd = open("./testPipe",O_WRONLY);
    if (fd<0)
    {
        printf("open pipe fail");
        return -1;
    }
    write(fd,write_buf,sizeof(write_buf));
    close(fd);
    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>

int main(int argc,char **argv[])
{
    int ret,fd;
    char read_buf[125];

    fd = open("./testPipe",O_RDONLY);
    if (fd<0)
    {
        printf("open pipe fail");
        return -1;
    }
    read(fd,read_buf,sizeof(read_buf));
    printf("read_buf:%s\n",read_buf);
    close(fd);
    return 0;
}

多线程

同步与锁机制

信号量灯

信号量灯是信号量的集合,可以对多个信号量同时进行P/V操作

接口

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

//创建/打开函数
int semget(key_t key,int nsems,int semflag);
/* key: 和信号灯关联的key值
 * nsems: 信号灯集包含的信号灯数目
 * semflag: 访问权限  IPC_CREAT|0666
 * 返回值: 成功返回信号灯id, 失败返回-1
 */

//控制函数
int semctl(int semid,int semnum,int cmd,...union senmun arg);
/* semid: 信号灯集id
 * semnum: 要修改的信号灯集编号
 * cmd: GETVAL 获取信号量灯的值
 *        SETVAL 设置信号量灯的值
 *        IPC_RMID 删除信号量灯
 * arg: 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)  */
 *        }
 */

//p/v操作函数
int semop(int semid,struct sembuf *opsptr,size_t nops);
/* semid:信号量灯集id
 * opsptr:操作指针
 *     struct sembuf{
 *         short sem_num; /* 要操作信号量灯的编号 */
 *        short sem_op;  /* 0:等待信号量灯的值变为0, 1:资源释放(V操作), -1:分配资源(P操作)  */
 *     }
 * nops: 要操作信号量灯的个数
 */

Client

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <string.h>

typedef struct 
{
    int size;
    char content[0];
}shm_buf;

#define READ_LOCK 0
#define WRITE_LOCK 1
union semun{
    int val;
    struct semid_ds *buf;
    unsigned short *array;
    struct seminfo *__buf;
};

void init_sem(int semid,int s[],int n)
{
    int i;
    union semun myun;
    for(i=0;i<n;i++){
        myun.val = s[i];
        semctl(semid,i,SETVAL,myun);
    }
}


void pv(int semid,int num,int op)
{
    struct sembuf buf;
    buf.sem_num = num;
    buf.sem_op = op;
    buf.sem_flg = 0;
    semop(semid,&buf,1);
}

int main(int argc, char const *argv[])
{
    int shmid,semid,s[]={0,1};
    int key;
    shm_buf *p;

    key = ftok("/",1);
    if (key<0){
        printf("create key fail\n");
        return -1;
    }
    printf("create key success key=0x%X\n",key);
    shmid = shmget(key,128,IPC_CREAT|0777);
    if(shmid<0){
        printf("create shared memory fail\n");
        return -1;
    }

    semid = semget(key,sizeof(s),IPC_CREAT|0666);
    if(semid<0){
        printf("create sem fail\n");
        return -1;
    }


    printf("create shared memory success ,shmid=%d\n",shmid);
    system("ipcs -m");
    p = (shm_buf *)shmat(shmid,NULL,0);
    if(p == NULL){
        printf("shmat fail\n");
        return -1;
    }
    printf("shmat success\n");
    while(1)
    {
        printf("input message: ");
        pv(semid,WRITE_LOCK,-1);
        fgets(p->content,128,stdin);
        p->size = strlen(p->content);
        pv(semid,READ_LOCK,1);
    }
    shmctl(shmid,IPC_RMID,NULL);
    semctl(semid,0,IPC_RMID);
    return 0;
}

Server

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <string.h>

typedef struct 
{
    int size;
    char content[0];
}shm_buf;

#define READ_LOCK 0
#define WRITE_LOCK 1
union semun{
    int val;
    struct semid_ds *buf;
    unsigned short *array;
    struct seminfo *__buf;
};

void init_sem(int semid,int s[],int n)
{
    int i;
    union semun myun;
    for(i=0;i<n;i++){
        myun.val = s[i];
        semctl(semid,i,SETVAL,myun);
    }
}


void pv(int semid,int num,int op)
{
    struct sembuf buf;
    buf.sem_num = num;
    buf.sem_op = op;
    buf.sem_flg = 0;
    semop(semid,&buf,1);
}

int main(int argc, char const *argv[])
{
    int shmid,semid,s[]={0,1};
    int key;
    shm_buf *p;

    key = ftok("/",1);
    if (key<0){
        printf("create key fail\n");
        return -1;
    }
    printf("create key success key=0x%X\n",key);
    shmid = shmget(key,128,IPC_CREAT|0777);
    if(shmid<0){
        printf("create shared memory fail\n");
        return -1;
    }


    semid = semget(key,sizeof(s),IPC_CREAT|0666);
    if(semid<0){
        printf("create sem fail\n");
        return -1;
    }

    init_sem(semid,s,sizeof(s));

    printf("create shared memory success ,shmid=%d\n",shmid);
    system("ipcs -m");
    p = (shm_buf *)shmat(shmid,NULL,0);
    if(p == NULL){
        printf("shmat fail\n");
        return -1;
    }
    while(1)
    {
        pv(semid,READ_LOCK,-1);
        if (p->size>0){
            printf("shm buf:%s\n", p->content);
            p->size = 0;
        }
        pv(semid,WRITE_LOCK,1);
    }
    shmctl(shmid,IPC_RMID,NULL);
    semctl(semid,0,IPC_RMID);
    return 0;
}

内存管理

Socket编程

接口

//Socket函数,用于创建一个socket
int socket(int domain,int type,int protocol);
/* domain: 主机采用的通信协议族, AF_UNIT用于Unit系统的系统进程间通信,AF_INET用于Internet
 * type: 通信协议,SOCK_STREAM表示TCP,SOCK_DGRAM表示UDP协议
 * protocal:填0
 */

//bind函数
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
/* sockfd: socket文件描述符
 * my_addr: socket地址的指针
 * addrlen: socket地址长度
 */

//listen函数
int listen(int sockfd,int backlog);
/* sockfd:绑定后的socker描述符
 * backlog:请求排队的最大长度
 */

//accept函数
int accept(int sockfd, struct sockaddr *addr,int *addrlen);
/* sockfd:listen后的socker文件描述符
 * addr,addren:客户端地址指针和地址长度
 */

//connect函数
int connect(int sockfd, struct sockaddr * serv_addr,int addrlen);
/* sockfd:socket文件描述符
 * serv_addr:储存服务器端的连接信息
 * addrlen:serv_addr长度
 */

//send函数
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
/* sockfd: socket文件描述符
 * buf:发送数据的缓冲区
 * len:发送数据长度
 * flags:填0
 */

//recv函数
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
/* sockfd:socket文件描述符
 * buf:接收缓冲区
 * len:指明buf的长度
 * flag:填0
 */

//recvfrom函数,用于无连接套接字
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);
/* sockfd:socket文件描述符
 * buf:接收缓冲区
 * src_addr: 保存源机的IP和端口
 * addlen:sizeof(struct sockaddr)
 */

//sendto函数
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                      const struct sockaddr *dest_addr, socklen_t addrlen);
/* dest_addr:目的IP和端口
 * addrlen: sizeof(struct sockaddr)
 * sendto: 时间发送的数据字节长度
 */

TCP

image.png

客户端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socker.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h

#define SERVEER_PORT 8081

int main(void)
{
    int ret;
    int client_socket;
    struct sockaddr_in socket_server_addr;
    int addr_len;
    unsigned char buf[512];
    int len;

    client_socket = socket(AF_INET,SOCK_STREAM,0);
    if (client_socket == -1)
    {
        printf("socket error");
        return -1;
    }
    socket_server_addr.sin_family = AF_INET;
    socket_server_addr.sin_port = htons(SERVER_PORT);
    if (inet_aton(argv[1],&socket_server_addr.sin_addr) == 0)
    {
        printf("invalid server ip");
        return -1;
    }

    memset(socket_server_addr.sin_zero,0,8);
    ret = connect(client_socket,(const struct sockaddr *)&socket_server_addr,
                                                      sizeof(struct sockaddr));
    if(ret == -1)
    {
        printf("connect error");
        return -1;
    }
    while(1)
    {
        if (fgets(buf,sizeof(buf),stdin))
        {
            len = send(client_socket,buf,strlen(buf),0);
            if (len <= 0)
            {
                close(client_socket);
                return -1;
            }
        }
    }
    close(client_socket);
    return 0;
}

服务器端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>

#define SERVER_PORT 8180
#define C_QUEUE     10

int main(int argc, char **argv)
{
    char buf[512];
    int len;
    int duty_socket;
    int customer_socket;
    struct sockaddr_in socket_server_addr;
    struct sockaddr_in socket_client_addr;
    int ret;
    int addr_len;

    signal(SIGCHLD,SIG_IGN);//父进程死后,让init进程接管子进程,避免子进程成为僵尸进程
    duty_socket = socket(AF_INET,SOCK_STREAM,0);
    if(duty_socket == -1)
    {
        printf("socket error");
        return -1;
    }
    socket_server_addr.sin_family = AF_INET;
    socket_server_addr.sin_port = htons(SERVER_PORT);
    socket_server_addr.sin_addr.s_addr = INADDR_ANY;
    memset(socket_server_addr.sin_zero,0,8);

    ret = bind(duty_socket,(const struct sockaddr *)&socket_server_addr,
                                                      sizeof(struct sockaddr));
    if (ret == -1)
    {
        printf("bind error");
        return -1;
    }
    ret = listen(duty_socket,C_QUEUE);
    if (ret == -1)
    {
        printf("listen error");
        return -1;
    }
    while(1)
    {
        addr_len = sizeof(struct sockaddr);
        customer_socket = accept(duty_socket,(struct sockaddr *)&socket_client_addr,
                                                                         &addr_len);
        if(customer_socket != -1)
        {
            printf("Get connect from %s\n",inet_ntoa(socket_client_addr.sin_addr));
        }
        if (!fork())
        {
            while(1)
            {
                memset(buf,512,0);
                len = recv(customer_socket,buf,sizeof(buf),0);
                buf[len] = '\0';
                if (len <= 0)
                {
                    close(customer_socket);
                    return -1;
                }
                else
                {
                    printf("Get connect from %s, Msg is %s\n",
                                           inet_ntoa(socket_client_addr.sin_addr),buf);
                }
            }
        }
    }
    close(duty_socket);
    return 0;
}

UDP

image.png

客户端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define SERVER_PORT  8180

int main(int argc, char **argv)
{
    unsigned char buf[512];
    int len;
    struct sockaddr_in socket_server_addr;
    int ret;
    int addr_len;
    int client_socket;

    if (argc != 2)
    {
        printf("Usage:\n");
        printf("%s <server_ip>\n",argv[0]);
        return -1;
    }

    client_socket = socket(AF_INET,SOCK_DRRAM,0);
    if (client_socket == -1)
    {
        printf("socket error");
        return -1;
    }

    socket_server_addr.sin_family = AF_INET;
    socket_server_addr.sin_port = htons(SERVER_PORT);
    if (inet_aton(argv[1], &socket_server_addr.sin_addr) == 0)
    {
        printf("invalid server ip\n");
        return -1;
    }
    memset(socket_server_addr.sin_zero,0,8);

    while(1)
    {
        if (fgets(buf,sizeof(buf),stdin))
        {
            addr_len = sizeof(struct sockaddr);
            len = sendto(client_socket,buf,sizeof(buf),0,
                                     (struct sockaddr *)&socket_server_addr,addr_len);
            if (len <= 0)
            {
                close(client_socket);
                return -1;
            }
        }
    }
    close(client_socket);
    return 0;
}

服务器端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>

#define SERVER_PORT  8180

int main(int argc, char **argv)
{
    unsigned char buf[512];
    int len;
    int duty_socket;
    int customer_socket;
    struct sockaddr_in socket_server_addr;
    struct sockaddr_in socket_client_addr;
    int ret;
    int addr_len;

    duty_socket = socket(AF_INET,SOCK_DGRAM,0);
    if (duty_socket == -1)
    {
        printf("socket error");
        return -1;
    }

    socket_server_addr.sin_family = AF_INET;
    socket_server_addr.sin_port = htons(SERVER_PORT);
    socket_server_addr.sin_addr.s_addr = INADDR_ANY;
    memset(socket_server_addr.sin_zero,0,8);

    ret = bind(duty_socket,(const struct sockaddr *)&socket_server_addr,
                                                      sizeof(struct sockaddr));
    if (ret == -1)
    {
        printf("bind error");
        return -1;
    }

    while(1)
    {
        addr_len = sizeof(struct sockaddr);
        len = recvfrom(duty_socket,buf,sizeof(buf),0,
                                  (struct sockaddr *)&socket_client_addr,&addr_len);
        if (len > 0)
        {
            buf[len] = '\0';
            printf("Get Msg from %s : %s\n",inet_ntoa(socket_client_addr.sin_addr),buf);
        }
    }
    close(duty_socket);
    return 0;
}