1,socket()不调用系统的socket()函数了,去调用自己封装的Socket()函数 dao
1,Socket() :创建监听套接字lfd
2,Bind():绑定地址结构 Strucr sockaddr_in addr;
3,Listen(): 设置同时监听上限
4,Accept():每Accept一次就会返回一个新的套接字,并且有一个新进程(子进程)与之对应,所以如果一个服务器支持与多个客户端进行连接的话,就应用loop实现
while(1)
{
cfd = Accept();//cfd接收客户端连接请求,lfd用于监听
pid = fork();//当有一个Accept返回了,就可以创建子进程(是用于与客户端连接的子进程)
if(pid == 0)//如果pid是0就是子进程,子进程就做相应工作,这边就是读内容转换成大写字符再写回客户端
{
close(lfd);//子进程只需要cfd,所以关闭用于建立连接的套接字lfd
read();
toUpper();
write();
}else if(pid>0)//pid>0是父进程
{
close(cfd);//只需要lfd用于监听,关闭用于与客户端通信的套接字cfd
//父进程是lfd,就用持续监听是否有新的客户来连接,有就产生新的套接字用于连接进行通信,即父进程就是调用Accept()函数,因此直接跳回到Accept(),continue就ok
continue;
}
}
重要:☆父进程还要回收子进程☆ 信号捕捉函数
5,
和多进程的区别:创建子进程fork()函数,创建子线程pthread_create()函数
前面都一样:
1,Socket() :
2,Bind():
3,Listen():
4,while(1)
{
cfd = Accpet(lfd, , );//cfd接收客户端连接请求,
pthread_create(&tid ,NULL ,tfn ,NULL );//启动子线程
pthread_detach(tid);//线程不能进行回收,可以用detach分离
}
5,子线程://与子进程做一样的事
void * tfn(void *arg)
{
close(lfd);//只用来连接 线程好像是不能关的,因为线程是同一份空间
read(cfd);
toUpper();
write(cfd);
}
1,创建lfd 接收socket,用自己封装的Socket函数就不用去检查返回值了
2,Bind(lfd,(强转)&地址结构,长度),服务器地址结构的定义与初始化,以及要记得添加相应头文件
3,listen()
4,循环中 :
4.1,accept():accept创建新套接字cfd,函数参数分别是lfd,客户端地址结构,客户端地址结构长度,长度的类型是socklen_t,要记一下的//用lfd创立连接返回cfd
4.2,创建子进程fork(),定义变量pid_t类型的pid = fork(),小于0报错,大于0是父进程,pid=0是子进程,子进程就可以关闭lfd,并可以开始处理(read,toupper,write)
4.3,read()要ret接收,从buf读,write写ret个到buf中,所以要定义ret,i,buf
5, 子进程回收 复习操作系统的信号之后补上//24.49开始
5,子进程回收:用信号捕捉函数进行子进程回收
5.1,
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include"wrap.h"
#DEFINE SRV_PORT 999
void catch_child(int signum)//捕捉到就可以去回收了
{
while(waitpid(0,NULL, WNOHANG)) > 0);//第一个参数0无差别回收所有子进程,但不循环就只能一次回收一次,所以循环多次回收
return;
}
int main(int argc, char *argv[])
{
int lfd,cfd;
pid_t pid;//进程
struct sockaddr_in srv_addr,clt_addr;//地址结构初始化
socklen_t clt_addr_len;
char buf[BUFSIZ];//读写需要的缓冲区
int ret, i;
//memset(&srv_addr,0,sizeof(srv_addr));//将地址结构清零,之后再去赋值
bzero(&srv_addr, sizeof(srv_addr));//memset一个作用,但是写法更简单,头文件
//初始化地址结构
srv_addr.sin_family = AF_INET;
srv_addr.sin_port = htons(SRV_PORT);
srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
lfd = Socket(AF_INET, SOCK_STREAM,0);//不用检查返回值了,wrap.h中已经写好了
Bind(lfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
Listen(lfd, 128);
clt_addr_len = sizeof(clt_addr);
while(1)
{
cfd = Accept(lfd,(struct sockaddr*)&clt_addr, &clt_addr_len);
pid = fork();//创建子进程
if(pid<0)
{
perr_exit("fork error");
}else if(pid == 0)//是子进程
{
close(lfd);
break;//跳出在外面操作
}else{
//信号用来回收子进程
struct sigaction act;
act.sa_handler(catch_child);
sigempthset(&act.sa_mask);
act.sa_flags = 0;
ret = sigaction(SIGCHLD,&act, NULL);//注册完
if(ret != 0)
{
perr_exit("sigaction error");
}
close(cfd);
continue;//继续去监听其他来连接的进程
}
}
if(pid == 0)//子进程
{
for(;;){
ret = Read(cfd, buf,sizeof(buf));
if(ret == 0)
{
//检测到客户端关闭了,就可以关闭退出了
close(cfd);
exit(1);//子进程退出
}
for(i = 0; i<ret; ++i)
buf[i] = toupper(buf[i]);//小写转大写结束
write(cfd, buf, ret);
write(STDOUT_FILENO, buf, ret);//写到桌面上
}
}
return 0;
}
还没有回收
信号回收部分:
struct sigaction act;
act.sa_handler(catch_child);
sigempthset(&act.sa_mask);
act.sa_flags = 0;
ret = sigaction(SIGCHLD,&act, NULL);//注册
void catch_child(int signum)//捕捉到就可以去回收了
{
while(waitpid(0,NULL, WNOHANG)) > 0);
return;
}
客户端服务端至少得ping通才能通信哇,要在一个局域网网段中??(桥接模式)
网络设置为NAT模式
scp -r 当前目录 目标位置