1. 程式人生 > >Linux網路程式設計 -- 多程序實現多使用者

Linux網路程式設計 -- 多程序實現多使用者

server.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <strings.h>
#include <sys/wait.h>

#include "wrap.h"

#define SERV_PORT 8888

void wait_child(int signo)
{
    //如果>0,繼續回收子程序
    while (waitpid(0
, NULL, WNOHANG) > 0) { ; } } int main() { int i; int n; int cfd; int opt = 1; int listenfd; //檔案描述符 pid_t pid; //程序號 char buf[BUFSIZ]; //存放讀取到的客戶端的資料 char clie_IP[BUFSIZ]; //用來存放客戶端IP socklen_t clie_addr_len; struct sockaddr_in serv_addr, clie_addr; //引數1: AF_INET ->ipv4 AF_INET6 ->ipv6
//引數2:SOCK_STREAM -> TCP SOCK_DGRAM -> UDP //引數3:傳0 表示使用預設協議。 listenfd = Socket(AF_INET, SOCK_STREAM, 0); //埠複用 setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); bzero(&serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(SERV_PORT); //主機位元組序轉換為網路位元組序 大端模式 小端模式
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); //網路地址為INADDR_ANY,這個巨集表示本地的任意IP地址 Bind(listenfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); //由於歷史原因,需強制轉換為 struct sockaddr * 型別 Listen(listenfd, 128); //允許同時監聽的客戶端請求, 最大128 while (1) { clie_addr_len = sizeof(clie_addr); cfd = Accept(listenfd, (struct sockaddr *)&clie_addr, &clie_addr_len); //當有客戶端連線 就建立一個程序 pid = fork(); if (0 == pid) { Close(listenfd); while (1) { n = Read(cfd, buf, sizeof(buf)); if (0 == n) { break; } printf("Client IP: %s, Port: %d\n", inet_ntop(AF_INET, &clie_addr.sin_addr.s_addr, clie_IP, sizeof(clie_IP)), ntohs(clie_addr.sin_port)); for (i = 0; i < n; ++i) { buf[i] = toupper(buf[i]); } Write(cfd, buf, n); } Close(cfd); return 0; } else if (pid > 0) { Close(cfd); //回收子程序,防止產生殭屍程序 signal(SIGCHLD, wait_child); } else { perr_exit("fork"); } } return 0; }

wrap.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>

//輸出錯誤資訊並退出
void perr_exit(const char *str)
{
    perror(str);
    exit(-1);
}    

//建立套接字 帶出錯處理  哈哈
int Socket(int family, int type, int protocol)
{
    int n;

    n = socket(family, type, protocol);
    if (n < 0)
    {
        perr_exit("socket error");
    }

    return n;
}


int Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
    int n;

    n = bind(fd, sa, salen);
    if (n < 0)
    {
        perr_exit("bing error");
    }

    return n;
}

int Listen(int fd, int backlog)
{
    int n;

    n = listen(fd, backlog);
    if (n < 0)
    {
        perr_exit("listen error");
    }

    return n;
}

int Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{
    int n;

    n = connect(fd, sa, salen);
    if (n < 0)
    {
        perr_exit("connect error");
    }

    return n;
}

int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{
    int n;

again:
    n = accept(fd, sa, salenptr);
    if (n < 0)
    {
        if (errno == ECONNABORTED || errno == EINTR)
        {
            goto again;
        }
        else
        {
            perr_exit("accept error");
        }
    }
}

ssize_t Read(int fd, void *ptr, size_t nbytes)
{
    ssize_t n;

again:
    n = read(fd, ptr, nbytes);
    if (-1 == n)
    {
        if (EINTR == errno)
        {
            goto again;
        }
        else
        {
            return -1;
        }
    }

    return n;
}

ssize_t Write(int fd, const void *ptr, size_t nbytes)
{
    ssize_t n;

again:
    n = write(fd, ptr, nbytes);
    if (-1 == n)
    {
        if (EINTR == errno)
        {
            goto again;
        }
        else
        {
            return -1;
        }
    }

    return n;
}

int Close(int fd)
{
    int n;

    n = close(fd);
    if (-1 == n)
    {
        perr_exit("close error");
    }

    return n;
}