Linux網路程式設計 -- 多程序實現多使用者
阿新 • • 發佈:2019-01-06
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;
}