每连接一个客户端就fork一个子进程去处理,子进程结束,父进程要给子进程回收资源,假如是wait阻塞回收,不满足并发服务器要求。假如是waitpid非阻塞,轮询占资源。可以在子进程结束后给父进程发信号,父进程收到信号进行捕获,给子进程回收资源。
server.c
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define ERRLOG(ermsg) \
do { \
printf("%s %s %d:", __FILE__, __func__, __LINE__); \
perror(ermsg); \
exit(-1); \
} while (0)
void signal_handle(int signo)
{
wait(NULL);
}
int main(int argc, const char* argv[])
{
if (argc != 3) {
printf("retype!\n");
return -1;
}
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
ERRLOG("socket error");
}
// 填充服务器信息结构体
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[2]));
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
socklen_t serveraddr_len = sizeof(serveraddr);
if (-1 == bind(sockfd, (struct sockaddr*)&serveraddr, serveraddr_len)) {
ERRLOG("bind error");
}
if (-1 == listen(sockfd, 10)) {
ERRLOG("listen error");
}
// 定义客户端消息结构体
struct sockaddr_in clientaddr;
memset(&clientaddr, 0, sizeof(clientaddr));
socklen_t clientaddr_len = sizeof(clientaddr);
int acceptfd;
pid_t pid;
signal(SIGUSR1, signal_handle); // 信号处理函数,捕捉
while (1) {
// 等待客户端连接
acceptfd = accept(sockfd, (struct sockaddr*)&clientaddr, &clientaddr_len);
if (acceptfd == -1) {
ERRLOG("accept error");
}
// 客户端进来就fork一个进程,
pid = fork();
if (pid == -1) {
ERRLOG("fork error");
} else if (pid == 0) { // 子进程处理
char buf[128];
while (1) {
memset(buf, 0, sizeof(buf));
int ret = recv(acceptfd, buf, sizeof(buf), 0);
if (ret == -1) {
perror("recv error");
break;
}
if (ret == 0) {
printf("客户端[%s:%d]断开连接\n", inet_ntoa(clientaddr.sin_addr),
ntohs(clientaddr.sin_port));
break;
}
if (!strcmp("quit", buf)) {
printf("客户端[%s:%d]退出了\n", inet_ntoa(clientaddr.sin_addr),
ntohs(clientaddr.sin_port));
break;
}
printf("客户端[%s:%d]发来数据[%s]\n", inet_ntoa(clientaddr.sin_addr),
ntohs(clientaddr.sin_port), buf);
sprintf(buf, "%s-cmcc", buf);
if (-1 == send(acceptfd, buf, sizeof(buf), 0)) {
perror("send error");
break;
}
}
close(acceptfd);
kill(getppid(), SIGUSR1);
exit(0);
} else {
signal(SIGUSR1, signal_handle); // 信号处理函数,捕捉
close(acceptfd);
}
}
return 0;
}
client.c
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#define ERRLOG(ermsg) \
do { \
printf("%s %s %d:", __FILE__, __func__, __LINE__); \
perror(ermsg); \
exit(-1); \
} while (0)
int main(int argc, const char* argv[])
{
if (argc != 3) {
printf("Usage : %s <IP> <PORT>\n", argv[0]);
return -1;
}
// 1创建套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0); // AF_INET:IPV4,SOCK_STREAM:TCP
if (-1 == sockfd) {
ERRLOG("socket error");
}
// 2填充服务器网络信息结构体
struct sockaddr_in serveraddr = {
.sin_family = AF_INET,
.sin_port = htons(atoi(argv[2])), // 端口号 argv[2]输入进来的是char *字符串,需要转换成数用atoi
.sin_addr.s_addr = inet_addr(argv[1]), // IP地址
};
socklen_t serveraddr_len = sizeof(serveraddr);
char buf[128];
if (connect(sockfd, (struct sockaddr*)&serveraddr, serveraddr_len) == -1) {
ERRLOG("connect error");
}
printf("与服务器连接成功\n");
while (1) {
memset(buf, 0, sizeof(buf));
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf) - 1] = '\0';
if (-1 == send(sockfd, buf, sizeof(buf), 0)) {
ERRLOG("send error");
}
int ret = recv(sockfd, buf, sizeof(buf), 0);
if (ret == -1) {
ERRLOG("recv error");
}
if (ret == 0) {//服务器断开连接
break;
}
printf("接收的数据%s\n", buf);
}
close(sockfd);
return 0;
}