先与客户端建立好连接, 每次监听到一个客户端之后,都需要产生一个子进程去处理这个连接,然后父进程继续去等待监听,唯一一个要注意的点就是要使用信号来监听子进程是否结束,从而对其进行回收,防止僵尸进程的产生。。。
这里使用的是Ipv4,TCP套接字,所以使用的接口是:lfd = socket(AF_INET, SOCK_STREAM, 0)
如果是IPV6把AF_INET后面加个6,如果是UDP,那就是把第二个改成SOCK_DGRAM;
主要是端口复用:固定写法就好,第一个参数是socket函数返回值套接字的文件描述符:int opt = 1; setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
bind(lfd, (struct sockaddr*)&ser_addr, sizeof(ser_addr));
b这个函数主要目的就是将服务器的地址结构绑定到套接字lfd上,所以开始要设置服务器的ser_addr:ser_addr.sin_family = AF_INET, ser_addr.sin_port = htons(8888);ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
端口8888是可由自己设置的,,
设置监听的上限的函数,,并不是阻塞监听的函数listen(lfd, 128);
accept视为阻塞监听函数,cfd = accept(lfd, (struct sockaddr*)&cli_addr, &cli_addr_len);
这个函数主要是完成两个事情:(1)为了得到客户端的地址结构:也就是cli_addr,这个不需要初始化,因为accept函数会设置好,要注意的是cli_addr_len要初始化为sizeof(cli_addr),不然会报错;(2)会返回与客户端进行的通信的套接字cfd;
监听到了客户端后,就要开始创建子进程来对这个监听进行处理;pid = fork()
因为子进程不需要监听连接,使用可以close(lfd);之后便可以进行通信处理
void do_work(int cfd, ProcessTcp tcp){
char buf[BUFSIZ];
int ans = 5, n;
while (ans--){
n = tcp.Read(cfd, buf, sizeof(buf));
tcp.Write(cfd, buf, n);
tcp.Write(STDOUT_FILENO, buf, n);
}
}
父进程使用信号机制来对子进程回收
主要是通过sigaction函数
struct sigaction act;
act.sa_handler = catch_child;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
int sigaction(SIGCHLD, &act, NULL);
void catch_child(int sig){
while ((waitpid(-1, NULL, WNOHANG)) > 0);
}
ProcessTcp.h
#ifndef __PROCESSTCP_H_
#define __PROCESSTCP_H_
#include<iostream>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<strings.h>
#include<sys/socket.h>
#include<arpa/inet.h>
using namespace std;
class ProcessTcp{
public:
ProcessTcp(string note){
cout << note << endl;
}
int Socket(int domain, int type, int protocol){
int lfd = socket(domain, type, protocol);
if (lfd == -1){
cout << "socket() fail :" << strerror(errno) << endl;
exit(1);
}
return lfd;
}
void setSerAddr(struct sockaddr_in& ser_addr, int flg){
bzero(&ser_addr, sizeof(ser_addr));
ser_addr.sin_family = AF_INET;
ser_addr.sin_port = htons(8888);
if (flg == 1)
ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
else
inet_pton(AF_INET, "127.0.0.1", &ser_addr.sin_addr.s_addr);
}
void setSockOpt(int lfd){
int opt = 1;
int ret = setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if (ret == -1){
cout << "setsockopt() fail:" << strerror(errno) << endl;
}
}
void Bind(int lfd, const struct sockaddr* ser_addr, socklen_t ser_len){
int ret = bind(lfd, ser_addr, ser_len);
if (ret == -1){
cout << "bind() fail :" << strerror(errno) << endl;
exit(1);
}
}
void Listen(int lfd, int backlog){
int ret = listen(lfd, backlog);
if (ret == -1){
cout << "listen() fail :" << strerror(errno) << endl;
exit(1);
}
}
int Accept(int lfd, struct sockaddr* cli_addr, socklen_t* cli_len){
int cfd;
do{
cfd = accept(lfd, cli_addr, cli_len);
if (cfd == -1){
if (errno == EINTR)
continue;
else {
cout << "accept() --- error: " << strerror(errno) << endl;
exit(1);
}
}
}while(0);
return cfd;
}
int Connect(int cfd, const struct sockaddr *addr, socklen_t addrlen){
int ret = connect(cfd, addr, addrlen);
if (ret == -1){
cout << "connect() fail: " << strerror(errno) << endl;
exit(1);
}
return ret;
}
int Read(int fd, void *buf, size_t count){
int ret = read(fd, buf, count);
if (ret == 0){
close(fd);
cout << "the client close connection!!!" << endl;
exit(1);
} else if (ret == EAGAIN){
cout << "the error is EAGAIN" << endl;
exit(1);
} else if (ret > 0){
return ret;
}
return ret;
}
int Write(int fd, const void *buf, size_t count){
int ret = write(fd, buf, count);
return ret;
}
};
#endif
Process_tcp.cpp
#include "processTcp.h"
#include<signal.h>
#include<sys/wait.h>
void catch_child(int sig){
while ((waitpid(-1, NULL, WNOHANG)) > 0);
}
void do_work(int cfd, ProcessTcp tcp){
char buf[BUFSIZ];
int ans = 5, n;
while (ans--){
n = tcp.Read(cfd, buf, sizeof(buf));
tcp.Write(cfd, buf, n);
tcp.Write(STDOUT_FILENO, buf, n);
}
}
int main(){
int n, ret, ans, cfd;
pid_t pid;
struct sockaddr_in serv_addr, cli_addr;
socklen_t cli_addr_len;
ProcessTcp tcp("server is ok!!!!");
int lfd = tcp.Socket(AF_INET, SOCK_STREAM, 0);
tcp.setSockOpt(lfd);
tcp.setSerAddr(serv_addr, 1);
tcp.Bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
tcp.Listen(lfd, 128);
cout << "Now arrange receive other connection!!!" << endl;
while(1){
cli_addr_len = sizeof(cli_addr);
cfd = tcp.Accept(lfd, (struct sockaddr*)&cli_addr, &cli_addr_len);
pid = fork();
if (pid < 0){
cout << "fork() --- error: " << strerror(errno) << endl;
exit(1);
} else if (pid > 0){
close(cfd);
struct sigaction act;
act.sa_handler = catch_child;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
ret = sigaction(SIGCHLD, &act, NULL);
if (ret == -1){
cout << "sigaction() --- error:" << strerror(errno) << endl;
exit(1);
}
continue;
} else if (pid == 0){
close(lfd);
break;
}
}
do_work(cfd, tcp);
return 0;
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。