1、server.c
#include "wrap.h"
#include <ctype.h>
#include <strings.h>
#include <signal.h>
#include <wait.h>
typedef void (*sighandler_t)(int);
void sigchld_handler(int signal)
{
int wstatus;
pid_t pid = wait(&wstatus);
while(pid > 0){
printf("close pid %d success...\n", pid);
pid = wait(&wstatus);
}
}
void response_message(int sfd);
#define SERVER_PORT 3000
int main(){
int sfd, cfd;
// 1、socket
sfd = Socket(AF_INET, SOCK_STREAM, 0);
// 2、bind
struct sockaddr_in sockaddr;
bzero(&sockaddr, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(SERVER_PORT);
sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
// inet_pton(AF_INET, "10.211.55.6", &sockaddr.sin_addr.s_addr);
Bind(sfd, &sockaddr, sizeof(sockaddr));
// 3、listen
Listen(sfd, 128);
while(1){
// 4、开启监听accept
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
socklen_t length = sizeof(addr);
cfd = Accept(sfd, &addr, &length);
char buf[BUFSIZ];
bzero(buf, BUFSIZ);
printf("Client connected ip:%s, port:%d\n", inet_ntop(AF_INET, &addr.sin_addr.s_addr, buf, BUFSIZ), ntohs(addr.sin_port));
pid_t pid = fork();
if (pid < 0){
perror("fork error");
exit(1);
}else if(pid == 0){
// 子进程
close(sfd);
break;
}else{
// 父进程,注册信号捕获
sighandler_t handler = signal(SIGCHLD, sigchld_handler);
if (handler == SIG_ERR){
perror("signal error");
exit(1);
}
close(cfd);
}
}
// 子进程
if (pid == 0){
while(1){
response_message(cfd);
}
}
return 0;
}
// 客户端消息处理函数
void response_message(int cfd)
{
char buf[BUFSIZ];
int i;
ssize_t n = Readn(cfd, buf, BUFSIZ);
if (n == 0){
/*
struct sockaddr_in c_addr;
socklen_t length = sizeof(c_addr);
getsockname(cfd, (struct sockaddr *)&c_addr, &length);
printf("Client closed ip:%s port:%d\n",
inet_ntop(AF_INET, &c_addr.sin_addr.s_addr, buf, BUFSIZ),
ntohs(c_addr.sin_port));
*/
close(cfd);
exit(1);
}else if(n < 0){
close(cfd);
perror("read error");
exit(1);
}
for(i = 0; i < n; i++){
buf[i] = toupper(buf[i]);
}
write(cfd, buf, n);
}
wrap.h
#ifndef _WRAP_H_
#define _WRAP_H_
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int Socket(int domain, int type, int protocol);
int Bind(int sockfd, const struct sockaddr_in *addr, socklen_t addrlen);
int Listen(int sockfd, int backlog);
int Accept(int sockfd, struct sockaddr_in *addr, socklen_t *addrlen);
int Connect(int sockfd, const struct sockaddr_in *addr, socklen_t addrlen);
ssize_t Readn(int fd, void *buf, size_t count);
#endif
wrap.c
#include "wrap.h"
#include <errno.h>
void print_err(const char* descript)
{
perror(descript);
exit(1);
}
int Socket(int domain, int type, int protocol)
{
int ret = socket(domain, type, protocol);
if (ret < 1) print_err("socket error");
return ret;
}
int Bind(int sockfd, const struct sockaddr_in *addr, socklen_t addrlen)
{
int ret = bind(sockfd, (struct sockaddr *)addr, addrlen);
if (ret < 0) print_err("bind error");
return ret;
}
int Accept(int sockfd, struct sockaddr_in *addr, socklen_t *addrlen)
{
int sfd;
again:
sfd = accept(sockfd, (struct sockaddr *)addr, addrlen);
if (sfd < 0){
// 阻塞等待,考虑被信号中断的情况
if ((errno == ECONNABORTED) || (errno == EINTR)){
goto again;
}else{
print_err("accept error");
}
}
return sfd;
}
int Listen(int sockfd, int backlog)
{
int ret = listen(sockfd, backlog);
if (ret < 0) print_err("listen error");
return ret;
}
int Connect(int sockfd, const struct sockaddr_in *addr, socklen_t addrlen)
{
int ret = connect(sockfd, (struct sockaddr *)addr, addrlen);
if (ret < 0) print_err("connect error");
return ret;
}
ssize_t Readn(int fd, void *buf, size_t count)
{
size_t readed = 0;// 已读数
size_t remain = count;// 未读数
while(remain > 0){
int n = read(fd, buf+readed, remain);
if (n < 0){ // 异常处理
if (errno == EINTR){
n = 0;// 信号中断,继续循环
}else{
return n;// 异常情况直接返回
}
}else if (n < remain){
remain -= n;
break;
}
readed += n;
remain -= n;
}
return count - remain;// 返回应读数-未读数
}
运行结果:
parallels@ubuntu:~/Linux/mp-socket$ ./server.out
Client connected ip:10.211.55.2, port:49399
Client connected ip:10.211.55.2, port:49400
close pid 5702 success...
close pid 5745 success...
^C
parallels@ubuntu:~/Linux/mp-socket$
2、client.c
#include "wrap.h"
#include <unistd.h>
#include <string.h>
#define SERVER_PORT 3000
#define SERVER_IP "10.211.55.6"
int main(){
int sfd = Socket(PF_INET, SOCK_STREAM, 0);
struct sockaddr_in svr_addr;
svr_addr.sin_family = PF_INET;
svr_addr.sin_port = htons(SERVER_PORT);
// 清0操作
memset(&svr_addr.sin_addr.s_addr, 0, sizeof(svr_addr.sin_addr.s_addr));
// 将点分十进制字符串转为字节序
inet_pton(PF_INET, SERVER_IP, &svr_addr.sin_addr.s_addr);
// 发起网络连接
Connect(sfd, &svr_addr, sizeof(svr_addr));
printf("服务器连接成功!\n");
char buf[BUFSIZ];
while(1){
// 读取输入流
fgets(buf, sizeof(buf), stdin);
// 写入套接字
write(sfd, buf, strlen(buf));
// 读取服务器响应
int n = read(sfd, buf, sizeof(buf));
// 将结果输出到标准输出流
write(STDOUT_FILENO, buf, n);
}
close(sfd);
return 0;
}
运行结果
yusian@SianMac2:~/Linux/socket$ ./client.out
服务器连接成功!
adf
ADF
aaa
AAA
^C
yusian@SianMac2:~/Linux/socket$