2.16作业

  1. tcp服务器的多路重用

a),服务器端

#include<stdio.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>

#define  SPORT 2024 
#define  IP  "192.168.8.156"

#define  PRINTF_ERR(msg)\
        do{\
            printf("line__%d_",__LINE__);\
            perror(msg);\
        }while(0)

int main(int argc, const char *argv[])
{
    
    int sfd=0;
    //创建流式套接字
    sfd=socket(AF_INET,SOCK_STREAM,0);
    if(sfd<0)
    {
        PRINTF_ERR("socket");
        return -1;
    }
    //端口快速复用
    int reuse=1;
    if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) <0)
    {
        PRINTF_ERR("setsockopt");
        return -1;
    }

    //填充服务器地址信息结构体
     struct sockaddr_in sin;
     sin.sin_family=AF_INET;
     sin .sin_port=htons(SPORT);
     sin.sin_addr.s_addr=inet_addr(IP);

     //绑定服务器端口和IP
     if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin))<0)
     {
         PRINTF_ERR("bind");
        return -1;
     }
     //将套接字设置为监听
     if(listen(sfd,10)<0)
     {
         PRINTF_ERR("listen");
        return -1;
     }
     //创建select函数监听的文件描述符集合
     //类型为fd_set
     //清空集合并将要将听的文件描述符添加到集合中
     //添加到集合中使用 FD_SET
     fd_set readfds, tempfds;
     FD_ZERO(&readfds);
     FD_SET(0,&readfds);
     FD_SET(sfd,&readfds);
    //最大文件描述符
     int maxfd=sfd;
     ssize_t res=0;
     int sres=0;
     char buf[34]="";
     int new_sfd=0;
     struct sockaddr_in cin;
     socklen_t addrlen =sizeof(cin);
     struct sockaddr_in saveCin[1020];
     //循环监听readfds结合内的文件描述符的情况
     while(1)
     {
        tempfds=readfds;
        //因为要包括最大的文件描述符所以要讲maxfd+1,并接受返回的有情况变化的文件描述符个数
         sres=select(maxfd+1,&tempfds,NULL,NULL,NULL);
        if(sres>0)
        {  
            //因为select函数解除阻塞后会将没有发生情况的的文件描述符清空,只留下有情况变化的文件描述符
            //循环比较tempfds中的文件描述符的变化情况
            for(int i=0;i<=maxfd;i++)
            {
                //判断文件描述符是否在tempfds中
                if(FD_ISSET(i,&tempfds)==0) 
                {
                    continue ;
                }
                if(0 == i)     //键盘触发并将键盘获取的数据发送给客户端
                {
                    printf("触发键盘输入事件>>>\n");
                    int sendfd=0;
                    res=scanf("%d %s",&sendfd,buf);
                    while(getchar()!=10);
                    if(res!=2)
                    {
                        printf("请输入正确的格式  :sendfd buf\n");
                        continue;
                    }
                    buf[strlen(buf)-1]=0;
                    if(send(sendfd,buf,sizeof(buf),0)<0)
                    {
                        PRINTF_ERR("send");
                        continue ;
                    }
                    printf("[%s]发送文件描述符为[%d]\n",buf,sendfd);
                }
                else if(sfd == i)
                {
                    printf("触发客户端链接事件>>>\n");                                                              
                    new_sfd=accept(i,(struct sockaddr *)&cin,&addrlen);
                    if(new_sfd<0)
                    {
                        PRINTF_ERR("accept");
                        continue ;
                    }
                    printf("%d:客户端接入>>[%d:%s]\n",new_sfd,ntohs(cin.sin_port),inet_ntoa(cin.sin_addr));
                    saveCin[new_sfd-4]=cin;
                    if(new_sfd>maxfd)
                    {
                        maxfd=new_sfd;
                    }    
                    FD_SET(new_sfd,&readfds);
                }
                else     //客户端交互
                {
                    printf("触发客户端交互事件>>>\n");
                    res=recv(i, buf, sizeof(buf),0);
                    if(res<0)
                    {
                        PRINTF_ERR("recvfrom");
                        continue ;
                    }
                    else if(0==res)
                    {
                        printf("[%s |%d]:客户端断开!\n",inet_ntoa(saveCin[i-4].sin_addr),ntohs(saveCin[i-4].sin_port));
                        FD_CLR(i,&readfds);
                        close(i);
                        for(int j=maxfd;j>0;j--)
                        {
                            if(FD_ISSET(j,&readfds))
                            {
                                maxfd=j;
                                break;
                            }   
                        }
                    }
                    else{
                        //读取到之后打印出来
                        printf("[%s |%d]-[%d]:%s\n",inet_ntoa(saveCin[i-4].sin_addr),ntohs(saveCin[i-4].sin_port),i,buf);
                        strcat(buf,"*==*");
                        if(send(i,buf,sizeof(buf),0)<00)
                        {
                            PRINTF_ERR("send");
                            return -1;
                        }
                    }
                }
            }
        }else if(0==sres)
        {
            break;
            
        }else 
        {
            PRINTF_ERR("select");
            return -1;
        }
     }
     close(sfd);
    return 0;
}

b ),客户端

#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<sys/time.h>
#include<unistd.h>
#include<string.h>

#define  SPORT  2024
#define   IP   "192.168.8.156"

#define  PRINTF_ERR(msg)\
    do{\
        printf("[line:_%d_]\n",__LINE__);\
        perror("msg");\
    }while(0)

int main(int argc, const char *argv[])
{
    //创建流式套接字
    int sfd=0;
    sfd=socket(AF_INET,SOCK_STREAM,0);
    if(sfd<0)
    {
        PRINTF_ERR("socket");
        return -1;
    }
    //填充服务器地址信息结构体
    struct sockaddr_in sin;
    struct sockaddr_in cin;
    sin.sin_family=AF_INET;
    sin.sin_port=htons(SPORT);
    sin.sin_addr.s_addr=inet_addr(IP);

    //连接服务器
    if(connect(sfd,(struct sockaddr *)&sin,sizeof(sin))<0)
    {
        PRINTF_ERR("connect");
        return -1;
    }
    //创建监听集合
    fd_set readfds;
    fd_set tempfds;
    FD_ZERO(&readfds);
    FD_SET(0,&readfds);
    FD_SET(sfd,&readfds);
    char buf[128]="";
    int s_res=0;
    int max_fd;
    max_fd=sfd;
    int res=0;
    //循环监听文件描述符集合
    while(1)
    {
        tempfds=readfds;
        s_res=select(max_fd+1,&tempfds,NULL,NULL,NULL);
        if(s_res>0)
        {
            for(int i=0;i<=max_fd;i++)
            {
                if(FD_ISSET(i,&tempfds)==0)
                {
                    continue;
                }
                if(0==i)
                {
                    //发送数据给服务器
                    printf("键盘触发事件>>>!\n");
                    memset(buf,0,sizeof(buf));
                    res=read(i,buf,sizeof(buf));
                    buf[strlen(buf)-1]=0;
                    if(res<0)
                    {
                        PRINTF_ERR("read");
                        return -1;
                    }
                    printf("[ %s ]以发送给服务器\n",buf);
                    if(send(sfd,buf,res,0)<0)
                    {
                        PRINTF_ERR("send");
                        return -1;
                    }
                }
                else if(sfd==i)
                {
                    printf("服务器连接触发>>>\n");
                    //接收服务器数据
                    res=recv(sfd,buf,sizeof(buf),0);
                    if(res<0)
                    {
                        PRINTF_ERR("msg");
                        return -1;
                    }else if(0==res)
                    {
                        printf("服务器端断开!\n");
                        close(sfd);
                        return 0;
                    }
                    printf("server>>>>%s\n",buf);
                }
            }
        }
        else if(0==s_res)
        {
            printf("time out !\n");
            return -1;
        }
        else
        {
            PRINTF_ERR("select");
            return -1;
        }
    }
    //关闭文件描述符
    close(sfd);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值