Linux网络编程和TCP服务器的多种实现

TCP

客户端:bind(addr)   connect()    send()    recv()   close()

服务端:fd=socket()  bind(addr)  listen()   clientfd = accept()  recv()   close()

listen只做迎接客户端的操作,不会影响后续工作(三次握手是在listen时确定的)

UDP

客户端:sendto()  recvfrom()

服务端:socket()  recvfrom(fd,addr,buffer,length,0)  sendto()

一个函数涉及的工作越单一,复用性就越强

recvfrom不仅负责接收数据,还获得了发送方的地址

UDP服务器如何做多个客户端的并发?

1.数据包上加一层协议:前提是收端能够恢复顺序

2.为了真正区分每个客户端,一个fd用来recvfrom,然后用一个新的fd做sendtoA(模拟TCP三次握手)

socket

int sockfd = socket();   相当于open打开一个文件 

socket=插座   

fd=(sip dip sport dport protocol) 是网络通信的句柄,文件描述符(IO属性),也可以当作一个客户端

从sigio谈信号

sigio    操作系统收到数据以后,发送sigio信号给服务器的进程

比如:kill -9 1234  操作系统给进程1234发一个信号id(-9)

信号接收 fd-->sigio   

UDP每接收到一个包触发一次sigio

TCP处理的时候sigio会很多,如何让os不发送sigio? TCP中采用epoll来代替了sigio

#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>


int sockfd;

void do_sigio(int signo){

    char buffer[256] = {0};
    struct sockaddr_in cli_addr;
    int clilen = sizeof(struct sockaddr_in);
    
    int len = recvfrom(sockfd, buffer, 256, 0, (struct sockaddr*)&cli_addr, &clilen);
    printf("Recv Message: %s\r\n", buffer);
                                             
    sendto(sockfd, buffer, len, 0, (struct sockaddr*)&cli_addr, clilen);

}

int main(){

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    signal(SIGIO, do_sigio);   //设置SIGIO信号处理函数

    struct sockaddr_in serv_addr;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(8888);
    serv_addr.sin_addr.s_addr = INADDR_ANY;

    // 改便文件描述符性质
    fcntl(sockfd, F_SETOWN, getpid());      // 设置用来接受SIGIO信号的进程
    
    int flags = fcntl(sockfd, F_GETFL, 0); //得到文件描述符的状态标志集
    flags |= O_ASYNC | O_NONBLOCK;         //为状态标志集添加O_ASYNC异步输入属性和非阻塞属性
    fcntl(sockfd, F_SETFL, flags);
    
    bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));


    while(1) sleep(1);

}

 

对于UDP,只要网卡收到数据就会触发操作系统发送sigio信号,进程执行do_sigio函数进行响应;

在TCP中,sigio会很多,多路复用采用select/poll/epoll进行。

1. 进程内部如何保存信号集合?

Linux中有31种信号(sigint,sigterm,sigio...)

每个信号都有一个int的数,对应了action数组的一个位置

sigaction->action[64]存储了所有信号集合

2. signal如何保存到进程的对应位置?

signal()---->内核调用do_sigaction()函数

比如sigio是29,就会把它存储到action[28]中

3. 进程如何发送信号?

kill -9 1234

对于系统调用sys_kill(int pid, int sig) 函数表示给某个进程pid发信号SIGKILL,不会发生阻塞,直接退出进程

多路IO复用  select/poll/epoll

select(maxfd+1, 可读集合, 可写集合, 有带外数据集合,超时时间);  需要三个数组  maxfd+1:io数量=fd个数

poll(pfd, length, timeout); 定时,在timeout时间内返回

epoll  epoll_create(int size) 这里的size没有太大意义 只要大于0就可以 

epoll_ctl(); 添加/删除一个io

epoll_wait(epfd, events,length,timeout);

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值