socket编程(三)

来源:互联网 发布:线切割3b编程实例宝剑 编辑:程序博客网 时间:2024/06/10 13:10

REUSEADDR

  • 服务器端尽可能使用REUSEADDR
  • 在绑定之前尽可能调用setsocketopt来设置REUSEADDR套接字选项
  • 使用REUSEADDR选项可以使得不必等待TIME_WAIT状态消失就可以重启服务器
    int on = 1;//选项开启标志    //设置地址重复利用    if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0){        perror("setsockopt error.");        exit(1);    }

处理多客户端连接

  • 一个连接由一个子进程来处理并发
pid_t pid;    while(1){        if((conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen)) < 0){            perror("accept() error.");            exit(1);        }        printf("ip = %s, port = %d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));        //一旦获得一个连接就创建一个进程出来        pid = fork();        if(pid == -1){            perror("fork error");            exit(1);        }        //子进程        if(pid == 0){            close(listenfd);            char recvbuf[1024];            while(1){                memset(recvbuf, 0, sizeof(recvbuf));                int ret = read(conn, recvbuf, sizeof(recvbuf));                //捕捉客户端关闭                if(ret == 0){                    printf("client close\n");                    break;                } else if(ret == -1) {                    perror("read erro");                    exit(1);                }                fputs(recvbuf, stdout);                write(conn, recvbuf, ret);            }            //销毁客户端开辟的进程            exit(EXIT_SUCCESS);        } else {            close(conn);        }    }

聊天程序实现

  • 用多进程方式实现点对点聊天
    • 一个进程用来获得输入,一个进程用来获得对方发来的消息

客户端

//p2pcli.c#include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netinet/in.h>#include <sys/types.h>#include <unistd.h>#include <errno.h>#include <signal.h>void handler(int sig){    exit(EXIT_SUCCESS);}int main(){    int sock;    //创建一个套接字    if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0){        perror("Creat socket failed.");        exit(1);    }    /*int socket(int domain, int type, int protocol);*/    struct sockaddr_in servaddr;    memset(&servaddr, 0, sizeof(servaddr));    servaddr.sin_family = AF_INET;    servaddr.sin_port = htons(9000);    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");    /*servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");*/    /*inet_aton("127.0.0.1", &servaddr.sin_addr);*/    if(connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){        perror("connect() error");        exit(1);    }    //    pid_t pid;    pid = fork();    if(pid == -1){        perror("fork() error");    }    if(pid == 0){        //子进程接收对方发送的数据        char recvbuf[1024] = {0};        while(1){            memset(recvbuf, 0, sizeof(recvbuf));            int ret = read(sock, recvbuf, sizeof(recvbuf));            if(ret == -1){                perror("read() error");                exit(1);            } else if(ret == 0){                printf("peer close\n");                break;            }            fputs(recvbuf, stdout);        }        close(sock);        kill(getppid(), SIGUSR1);//通知父进程退出        exit(EXIT_SUCCESS);    } else {        //主进程发送数据        signal(SIGUSR1, handler);        char sendbuf[1024] = {0};        while(fgets(sendbuf, sizeof(sendbuf), stdin) != NULL){            write(sock, sendbuf, strlen(sendbuf));            memset(sendbuf, 0, sizeof(sendbuf));        }        close(sock);        exit(EXIT_SUCCESS);    }    return 0;}

服务器端

//p2pserv.c#include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netinet/in.h>#include <sys/types.h>#include <unistd.h>#include <errno.h>#include <signal.h>void handler(int sig){    exit(EXIT_SUCCESS);}int main(){    int listenfd;    //创建一个套接字    if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){        perror("Create socket failed.");        exit(1);    }    /*int socket(int domain, int type, int protocol);*/    struct sockaddr_in servaddr;    memset(&servaddr, 0, sizeof(servaddr));    servaddr.sin_family = AF_INET;    servaddr.sin_port = htons(9000);    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);    /*servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");*/    /*inet_aton("127.0.0.1", &servaddr.sin_addr);*/    int on = 1;//选项开启标志    //设置地址重复利用    if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0){        perror("setsockopt error.");        exit(1);    }    if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){        perror("bind error.");        exit(1);    }    //绑定    if(listen(listenfd, SOMAXCONN) < 0){        perror("listen() error.");        exit(1);    }    //监听    struct sockaddr_in peeraddr;    socklen_t peerlen = sizeof(peeraddr);    int conn;    if((conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen)) < 0){        perror("accept() error");        exit(1);    }    printf("ip = %s, port = %d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));    //    pid_t pid;    pid = fork();    if(pid == -1){        perror("fork() error");        exit(1);    }    if(pid == 0){        //发送数据的子进程        signal(SIGUSR1, handler);        char sendbuf[1024] = {0};        while(fgets(sendbuf, sizeof(sendbuf), stdin) != NULL){            write(conn, sendbuf, strlen(sendbuf));            memset(sendbuf, 0, sizeof(sendbuf));        }        exit(EXIT_SUCCESS);    } else {        //父进程用于获取对方发送的数据        char recvbuf[1024];        while (1){            memset(recvbuf, 0, sizeof(recvbuf));            int ret = read(conn, recvbuf, sizeof(recvbuf));             if(ret == -1){                perror("read error");                exit(1);            } else if(ret == 0){                printf("peer close\n");                break;            }            fputs (recvbuf, stdout);        }        kill(pid, SIGUSR1);//通知子进程退出        exit(EXIT_SUCCESS);    }    return 0;}

实验结果

这里写图片描述

原创粉丝点击