网络编程(8.14)TCP并发服务器模型

这篇具有很好参考价值的文章主要介绍了网络编程(8.14)TCP并发服务器模型。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

作业:
1. 多线程中的newfd,能否修改成全局,不行,为什么?
2. 多线程中分支线程的newfd能否不另存,直接用指针间接访问主线程中的newfd,不行,为什么?
多线程并发服务器模型原代码:

#include<stdio.h>
#include<head.h>
#include<netinet/in.h>
#define PROT 1112
#define IP "192.168.125.133"
void handler(int sig)
{
    while(waitpid(-1,NULL,WNOHANG)>0);
}
struct climsg
{
    int nfd;
    struct sockaddr_in cin;
    
};
void* deal_cli_msg(void *arg);
int main(int argc, const char *argv[])
{
    //捕获17信号
    if(signal(17,handler)==SIG_ERR)
    {   
        ERR_MSG("signal");
        return -1; 
    }   
    //创建流式套接字
    int sfd=socket(AF_INET,SOCK_STREAM,0);
    if(sfd<0)
    {   
        ERR_MSG("socket");
        return -1; 
    }   
    printf("sfd=%d\n",sfd);
    //设置允许端口被快速复用
    int reuse=1;
    if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0)
    {   
        ERR_MSG("setsockopt");
        return -1; 
    }   
    printf("允许端口快速复用成功\n");
    //绑定服务器的IP和端口--->必须绑定
    struct sockaddr_in sin;
    sin.sin_family      = AF_INET;//必须填AF_INET
    sin.sin_port        = htons(PROT);//端口号:1024~49151
    sin.sin_addr.s_addr = inet_addr(IP);//本机IP
    if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
    {   
        ERR_MSG("bind");
        return -1; 
    }   
    printf("绑定成功\n");

    //将套接字设置为被动监听状态
    if(listen(sfd,128)<0)
    {   
        ERR_MSG("listen");
        return -1; 
    }   
    printf("被动监听状态设置成功\n");
    
    //从已完成连接的队列中获取一个客户端信息,生成一个新的文件描述符
    struct sockaddr_in cin;//存储客户端地址信息
    socklen_t addrlen = sizeof(cin);
    pthread_t tid;
    int nfd=-1;
    struct climsg info;
    while(1)
    {   
        nfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);
        if(nfd<0)
        {
            ERR_MSG("accept");
            return -1; 
        }
        printf("[%s:%d]nfd=%d,客户端连接成功\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),nfd);
        info.nfd=nfd;
        info.cin=cin;
        //该文件描述符才是客户端通信的文件描述符
        if(pthread_create(&tid,NULL,deal_cli_msg,(void *)&info)!=0)
        {
            printf("pthread_create failed __%d__\n",__LINE__);
            return -1; 
        }
    }   
    close(sfd);
    return 0;
}
void* deal_cli_msg(void *arg)
{
    char buf[128]="";
    ssize_t res=0;
    int nfd =((struct climsg*) arg)->nfd;
    struct sockaddr_in cin =((struct climsg*) arg)->cin;
    while(1)
    {   
        bzero(buf,sizeof(buf));
        //接受数据
        res=recv(nfd,buf,sizeof(buf),0);
        if(res<0)
        {
            ERR_MSG("recv");
            break;
        }
        else if(0==res)
        {
            printf("[%s:%d]nfd=%d 客户端下线\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),nfd);
            break;
        }
        printf("nfd=%d : %s\n",nfd,buf);
        //发送数据
        strcat(buf,"*_*");
        if(send(nfd,buf,sizeof(buf),0)<0)
        {
            ERR_MSG("send");
            break;
        }
        printf("发送成功\n");
    }
    close(nfd);
    return 0;                                                                                                                                                                                                                                                                                                                                                                                                                                                           
} 

1.将newfd改成全局变量效果:

网络编程(8.14)TCP并发服务器模型,服务器,算法,c语言,xmind,网络协议,tcp/ip,网络

 答:不行,因为newfd是全局变量的话,客户端连接后生成的新的文件描述符会一直覆盖上一次保存的文件描述符,导致客户端下线时只能关闭最新创建的文件描述符,无法关闭之前客户端连接时创建的文件描述符。

2.不保存分支线程的newfd,直接用指针间接访问主线程中的newfd效果:

网络编程(8.14)TCP并发服务器模型,服务器,算法,c语言,xmind,网络协议,tcp/ip,网络

与第一题效果相同,不保存nfd时有客户端创建连接会一直覆盖结构体里的文件描述符nfd的数据,导致断开连接时关闭的文件描述符nfd取的是结构体里最新的 ,导致之前创建连接时开启的文件描述符没有被保存导致无法关闭。

3.基于UDP的TFTP文件传输

TFTP通信过程总结

  1. 服务器在69号端口等待客户端的请求
  2. 服务器若批准此请求,则使用 临时端口 与客户端进行通信。
  3. 每个数据包的编号都有变化(从1开始)
  4. 每个数据包都要得到ACK的确认,如果出现超时,则需要重新发送最后的数据包或ACK包
  5. 数据长度以512Byte传输的,小于512Byte的数据意味着数据传输结束。

网络编程(8.14)TCP并发服务器模型,服务器,算法,c语言,xmind,网络协议,tcp/ip,网络

 网络编程(8.14)TCP并发服务器模型,服务器,算法,c语言,xmind,网络协议,tcp/ip,网络

 下载代码:

#include<stdio.h>
#include<head.h>
#define PORT 69
int main(int argc, const char *argv[])
{
    char IP[128]="";
    printf("请输入IP:\n");
    scanf("%s",IP);
    char name[128]="";
    printf("请输入文件名:\n");
    scanf("%s",name);
    //创建报式套接字
    int sfd=socket(AF_INET,SOCK_DGRAM,0);
    if(sfd<0)
    {   
        ERR_MSG("socket");
        return -1; 
    }   
    printf("sfd=%d\n",sfd);
    //填充客户端自身的地址信息结构体,真实的地址信息结构体根据地址族指定
    //AF_INET : man 7 ip;                                                                                                                                                                                                                                                                                                                                                                                                                                               
    struct sockaddr_in sin;
    sin.sin_family      = AF_INET;//必须填AF_INET
    sin.sin_port        = htons(PORT);//服务器端口号:1024~49151
    sin.sin_addr.s_addr = inet_addr(IP);//服务器IP ifconfig查看
    ssize_t res=0;
    struct sockaddr_in rcvaddr;
    socklen_t addrlen = sizeof(rcvaddr);
    char data[516]="";//数据包
    char ACK[4]="";//ACK包
    size_t i=4;
    char *p=data;
    short *p1=(short*)data;
    *p1=htons(1);
    char *p2=data+2;
    strcpy(p2,name);
    char *p3=p2+strlen(p2)+1;
    strcpy(p3,"octet");
    //发送读写请求
    if(sendto(sfd,p,(i+strlen(p2)+strlen(p3)),0,(struct sockaddr*)&sin,sizeof(sin))<0)
        {   
            ERR_MSG("sendto");
            return -1; 
        }   
    bzero(data,sizeof(data));
    int fp=open(name,O_WRONLY|O_CREAT|O_TRUNC,0664);
    while(1)
    {   
        //接收数据
        res=recvfrom(sfd,data,sizeof(data),0,(struct sockaddr*)&rcvaddr,&addrlen);
        if(res<0)
        {   
            ERR_MSG("recvfrom");
            return -1; 
        }   
        if(write(fp,data+4,res-4)<0)
        {   
            ERR_MSG("write");
            close(fp);
            return -1; 
        }   
        if(res<516)
        {   
            printf("传输完毕\n");
            break;
        }
        //发送数据
        short *m1=(short *)ACK;
        *m1=htons(4);
        short *m2=m1+1;
        *m2=*((short *)data+1);
        if(sendto(sfd,ACK,i,0,(struct sockaddr*)&rcvaddr,sizeof(rcvaddr))<0)
        {
            ERR_MSG("sendto");
            return -1; 
        }
        bzero(data,sizeof(data));
        bzero(ACK,sizeof(ACK));
    }   
    //关闭文件描述符
    close(sfd);
    close(fp);
    return 0;
} 

上传代码:文章来源地址https://www.toymoban.com/news/detail-649608.html

到了这里,关于网络编程(8.14)TCP并发服务器模型的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • linux并发服务器 —— linux网络编程(七)

    C/S结构 - 客户机/服务器;采用两层结构,服务器负责数据的管理,客户机负责完成与用户的交互;C/S结构中,服务器 - 后台服务,客户机 - 前台功能; 优点 1. 充分发挥客户端PC处理能力,先在客户端处理再提交服务器,响应速度快; 2. 操作界面好看,满足个性化需求; 3.

    2024年02月09日
    浏览(61)
  • 【网络编程】高性能并发服务器源码剖析

      hello !大家好呀! 欢迎大家来到我的网络编程系列之洪水网络攻击,在这篇文章中, 你将会学习到在网络编程中如何搭建一个高性能的并发服务器,并且我会给出源码进行剖析,以及手绘UML图来帮助大家来理解,希望能让大家更能了解网络编程技术!!! 希望这篇文章能

    2024年04月15日
    浏览(39)
  • Linux学习之网络编程3(高并发服务器)

    Linux网络编程我是看视频学的,Linux网络编程,看完这个视频大概网络编程的基础差不多就掌握了。这个系列是我看这个Linux网络编程视频写的笔记总结。 问题: 根据上一个笔记,我们可以写出一个简单的服务端和客户端通信,但是我们发现一个问题——服务器只能连接一个

    2024年02月01日
    浏览(35)
  • 【Linux网络编程】网络编程套接字(TCP服务器)

    作者:爱写代码的刚子 时间:2024.4.4 前言:本篇博客主要介绍TCP及其服务器编码 只介绍基于IPv4的socket网络编程,sockaddr_in中的成员struct in_addr sin_addr表示32位 的IP地址 但是我们通常用点分十进制的字符串表示IP地址,以下函数可以在字符串表示和in_addr表示之间转换 字符串转in

    2024年04月14日
    浏览(52)
  • Linux网络编程:多进程 多线程_并发服务器

    文章目录: 一:wrap常用函数封装 wrap.h  wrap.c server.c封装实现 client.c封装实现 二:多进程process并发服务器 server.c服务器 实现思路 代码逻辑  client.c客户端 三:多线程thread并发服务器 server.c服务器 实现思路 代码逻辑  client.c客户端 ​​​​   read 函数的返回值 wrap.h  wrap

    2024年02月12日
    浏览(44)
  • 网络编程(一)TCP单进程服务器编程详解

    想要学习socket网络编程的读者一定要首先学好计算机网络的理论知识,包括 1)osi网络七层模型与ip四层模型 2)套接字含义 3)局域网通信过程 4)广域网通信过程 5)tcp,udp通信协议,在这两个协议中的连接建立,数据封装,传输过程,传输中可能遇到的问题的处理(差错控

    2024年02月15日
    浏览(33)
  • 【网络编程】demo版TCP网络服务器实现

    UDP和TCP的区别: 对于TCP协议有几个特点: 1️⃣ 传输层协议 2️⃣ 有连接(正式通信前要先建立连接) 3️⃣ 可靠传输(在内部帮我们做可靠传输工作) 4️⃣ 面向字节流 对于UDP协议有几个特点: 1️⃣ 传输层协议 2️⃣ 无连接 3️⃣ 不可靠传输 4️⃣ 面向数据报 可以看到

    2024年02月06日
    浏览(41)
  • 【网络编程】TCP流套接字编程(TCP实现回显服务器)

    Socket(既能给客户端使用,也能给服务器使用) 构造方法 基本方法: ServerSocket(只能给服务器使用) 构造方法: 基本方法: 客户端代码示例: 服务器代码示例: 运行结果: 代码执行流程: 服务器启动,阻塞在accept,等待客户端建立连接. 客户端启动.这里的new操作会触发和服务器之间建立连

    2024年04月25日
    浏览(52)
  • 计算机网络编程 | 并发服务器代码实现(多进程/多线程)

    欢迎关注博主 Mindtechnist 或加入【Linux C/C++/Python社区】一起学习和分享Linux、C、C++、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和技术。 专栏:《网络编程》 当涉及到构建高性能的服务

    2024年02月08日
    浏览(46)
  • 【Linux网络编程】高并发服务器框架 线程池介绍+线程池封装

    前言 一、线程池介绍 💻线程池基本概念 💻线程池组成部分 💻线程池工作原理  二、线程池代码封装 🌈main.cpp 🌈ThreadPool.h 🌈ThreadPool.cpp 🌈ChildTask.h  🌈ChildTask.cpp 🌈BaseTask.h 🌈BaseTask.cpp 三、测试效果 四、总结 📌创建线程池的好处 本文主要学习 Linux内核编程 ,结合

    2024年01月16日
    浏览(80)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包