多进程回声服务器/客户端【linux】

 

并发服务器端

 #include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <cstring>
#include <arpa/inet.h>
#include <signal.h>
#include <cstdlib>
#include <iostream>
using namespace std;
void child_over(int sig)//信号处理器
{
    int state;
    int child_pid = waitpid(-1, &state, WNOHANG);
    if(WIFEXITED(state))
    {
        printf("id = %d 的进程正常终止,返回值是 %d\n",
               child_pid, WEXITSTATUS(state));
    }
}
int main(int argc, char **argv)
{
    int ser_sock, cli_sock;
    char s[200];
    sockaddr_in ser_addr, cli_addr;
    struct sigaction act;
    act.sa_handler = child_over;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    sigaction(SIGCHLD, &act, 0);//信号注册函数

    ser_sock = socket(PF_INET, SOCK_STREAM, 0);

    int opt = 1;
    setsockopt(ser_sock, SOL_SOCKET, SO_REUSEADDR, &opt, 4);//端口地址再分配

    memset(&ser_addr, 0, sizeof(ser_addr));
    ser_addr.sin_family = AF_INET;
    ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    ser_addr.sin_port = htons(atoi(argv[1]));

    if(bind(ser_sock, (sockaddr *)&ser_addr, sizeof(ser_addr)) != 0)
        puts("bind error");
    if(listen(ser_sock, 5) != 0)
        puts("listen error");

    while(1)
    {
        socklen_t s_len = sizeof(cli_addr);
        cli_sock = accept(ser_sock, (sockaddr *)&cli_addr, &s_len);
        if(cli_sock == -1) continue;

        pid_t pid = fork();
        if(pid == 0)
        {
            close(ser_sock);
            int len;
            while(len = read(cli_sock, s, 100))
            {
                if(!len) break;
                s[len] = 0;
                printf("message from client : %s\n", s);
                write(cli_sock, s, len);
            }
            close(cli_sock);
            return 3;
        }
        else
            close(cli_sock);
    }
    close(ser_sock);
    return 0;
}

 

I/O分割的回声客户端

 

 #include <stdio.h>
#include <arpa/inet.h>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
using namespace std;
int main(int argc, char **argv)
{
    int sock;
    sockaddr_in ser_addr;
    char s[200];
    sock = socket(PF_INET, SOCK_STREAM, 0);
    if(sock == -1) puts("socket error");
    memset(&ser_addr, 0, sizeof(ser_addr));
    ser_addr.sin_family = AF_INET;
    ser_addr.sin_addr.s_addr = inet_addr(argv[1]);
    ser_addr.sin_port = htons(atoi(argv[2]));
    if(connect(sock, (sockaddr *)&ser_addr, sizeof(ser_addr)) == -1)
        puts("connect error");


    pid_t pid = fork();
    if(pid == 0)
    {
        while(1)
        {
            puts("wait for message...");
            scanf("%s", s);
            if(!strcmp(s, "q") || !strcmp(s, "Q"))
            {
                shutdown(sock, 1);
                break;
            }
            else
                write(sock, s, strlen(s));
            sleep(0.5);
        }
    }
    else
    {
        while(1)
        {
            int len = read(sock, s, 100);
            if(len == 0) break;
            s[len] = 0;
            printf("message from server:%s\n", s);
        }
    }
    close(sock);
    return 0;
}

 

 

 

客户端31行用shutdown而不用close的原因是:


注意:
1.如果有多个进程共享一个套接字,close每被调用一次,计数减1,直到计数为0时,也就是所用进程都调用了close,套接字将被释放。
2.在多进程中如果一个进程中shutdown(sfd, SHUT_RDWR)后其它的进程将无法进行通信. 如果一个进程close(sfd)将不会影响到其它进程.
3.shutdown,不考虑描述符的参考数,可选择中止一个方向的连接, 但是仅仅是断开连接,仍然需要close释放链接占用的文件描述符。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值