多线程
#include <iostream>
#include <stdlib.h>
#include "tcpsocket.hpp"
void *thr_start(void *arg)
{
long fd = (long)arg;//arg是一个指针有8个字节空间long也有8个字节空间
TcpSocket cli_sock;
cli_sock.SetFd(fd);
while(1) {
//通过新获取的通信套接字与客户端进行通信
std::string buf;
if (cli_sock.Recv(&buf) == false) {
cli_sock.Close();//通信套接字接收数据出错,关闭的是通信套接字
pthread_exit(NULL);//exit是退出进程
}
printf("client say:%s\n", &buf[0]);
std::cout << "server say:";
fflush(stdout);
buf.clear();
std::cin >> buf;
if (cli_sock.Send(buf) == false) {
cli_sock.Close();
pthread_exit(NULL);
}
}
//循环退出则关闭套接字
cli_sock.Close();
return NULL;
}
int main(int argc, char *argv[])
{
if (argc != 3) {
printf("em:./tcp_srv 192.168.122.132 9000\n");
return -1;
}
std::string ip = argv[1];
uint16_t port = atoi(argv[2]);
TcpSocket lst_sock;
CHECK_RET(lst_sock.Socket());//创建套接字
//#define CHECK_RET(q) if((q)==false){return -1;}
//if (lst_sock.Socket() == false) {return -1;}
CHECK_RET(lst_sock.Bind(ip, port));//绑定地址信息
CHECK_RET(lst_sock.Listen());//开始监听
while(1) {
TcpSocket cli_sock;
std::string cli_ip;
uint16_t cli_port;
//Accept类成员函数,使用的私有成员_sockfd就是lst_sock的私有成员
//cli_sock取地址传入,目的是为了获取accept接口返回的通信套接字描述符
bool ret = lst_sock.Accept(&cli_sock, &cli_ip, &cli_port);//获取新套接字
if (ret == false) {
//获取新连接失败,可以重新继续获取下一个
continue;
}
printf("new connect:[%s:%d]\n", cli_ip.c_str(), cli_port);
//-----------------------------------------------------
pthread_t tid;
//将通信套接字当作参数传递给线程,让线程与客户端进行通信
//cli_sock是一个局部变量--循环完了这个资源就会被释放
pthread_create(&tid, NULL, thr_start, (void*)cli_sock.GetFd());//线程
pthread_detach(tid);//不关心线程返回值,分离线程,退出后自动释放资源
//主线程不能关闭cli_sock套接字,因为多线程是共用描述符的
}
lst_sock.Close();
return 0;
}
多进程:
#include <iostream>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#include "tcpsocket.hpp"
void sigcb(int signo) {
//当子进程退出的时候就会像父进程发送SIGCHLD信号,回调这个函数
//waitpid返回值>0表示处理了一个退出的子进程
//waitpid<=0表示没有退出的子进程了
while(waitpid(-1, 0, WNOHANG) > 0);//一次回调循环将退出的子进程全部处理
}
int main(int argc, char *argv[])
{
if (argc != 3) {
printf("em:./tcp_srv 192.168.122.132 9000\n");
return -1;
}
std::string ip = argv[1];
uint16_t port = atoi(argv[2]);
signal(SIGCHLD, sigcb);
TcpSocket lst_sock;
CHECK_RET(lst_sock.Socket());//创建套接字
//#define CHECK_RET(q) if((q)==false){return -1;}
//if (lst_sock.Socket() == false) {return -1;}
CHECK_RET(lst_sock.Bind(ip, port));//绑定地址信息
CHECK_RET(lst_sock.Listen());//开始监听
while(1) {
TcpSocket cli_sock;
std::string cli_ip;
uint16_t cli_port;
bool ret = lst_sock.Accept(&cli_sock, &cli_ip, &cli_port);//获取新套接字
if (ret == false) {
continue;
}
printf("new connect:[%s:%d]\n", cli_ip.c_str(), cli_port);
//-------------------------------------------------
pid_t pid = fork();
if (pid == 0) {//子进程复制父进程--数据独有,代码共享
//让子进程处理与客户端通信
while(1) {
std::string buf;
if (cli_sock.Recv(&buf) == false) {
cli_sock.Close();//通信套接字接收数据出错,关闭的是通信套接字
exit(0);
}
printf("client:[%s:%d] say:%s\n", &cli_ip[0], cli_port, &buf[0]);
std::cout << "server say:";
fflush(stdout);
buf.clear();
std::cin >> buf;
if (cli_sock.Send(buf) == false) {
cli_sock.Close();
exit(0);
}
}
cli_sock.Close();
exit(0);
}
//父子进程数据独有,都会具有cli_sock,但是父进程并不通信
cli_sock.Close();//这个关闭对子进程没有影响,因为数据各自有一份
}
lst_sock.Close();
return 0;
}