网络编程 day 4

news2024/12/25 12:20:29

1、多进程并发服务器根据流程图重新编写

#include <myhead.h>



#define ERR_MSG(msg)  do{\
    fprintf(stderr, "__%d__:", __LINE__); \
    perror(msg);\
}while(0)

#define PORT 8888               //端口号,范围1024~49151
#define IP  "192.168.114.85"    //本机IP,ifconfig


int deal_cli_msg(int newfd,struct sockaddr_in cin);

//回收僵尸进程
void handler(int sig)
{
	while(waitpid(-1,NULL,WNOHANG) > 0);
}

int main(int argc, const char *argv[])
{
	if(signal(17,handler) == SIG_ERR)
	{
		ERR_MSG("signal");
		return -1;
	}
//创建流式套接字 socket
	int sfd = socket(AF_INET,SOCK_STREAM,0);
	if(sfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}

	printf("socket create success 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");
	
	int newfd = -1;
	struct sockaddr_in cin;
	socklen_t addrlen = sizeof(cin);
	pid_t cpid = -1;

	while(1)
	{
		//父进程只负责连接
		newfd = accept(sfd,(struct sockaddr*)&cin,&addrlen);
		if(newfd < 0)
		{
			ERR_MSG("newfd");
			return -1;
		}
		printf("[%s;%d]客户端连接成功 newfd=%d\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);

		//能运行到当前位置,则代表有客户端连接成功;子进程只负责交互
		cpid = fork();
		if(0 == cpid)
		{
			close(sfd);
			//子进程只负责与客户端交互
			deal_cli_msg(newfd,cin);
			exit(0);
		}

		close(newfd);
	}
	//关闭文件名描述符
	if(close(sfd) < 0)
	{
		ERR_MSG("close");
		return -1;
	}

	
	return 0;
}

int deal_cli_msg(int newfd, struct sockaddr_in cin)
{
	char buf[128] = "";
	ssize_t res = 0;
	while(1)
	{
		//清空字符串
		bzero(buf,sizeof(buf));//memset
		//接收
		res = recv(newfd,buf,sizeof(buf),0);
		if(res < 0)
		{
			ERR_MSG("recv");
			return -1;
		}
		else if(0 == res)
		{
			printf("[%s;%d]客户端下载 newfd=%d\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);
			break;
		}
		printf("[%s;%d] newfd=%d ; %s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd,buf);
		//发送
		strcat(buf,"*_*");
		if(send(newfd,buf,sizeof(buf),0) < 0) 
		{
			ERR_MSG("send");
			return -1;
		}
		printf("send success\n");

	}

	close(newfd);
	return 0;

}

2、多线程并发服务器重新写一遍

#include<myhead.h>

#define ERR_MSG(msg)  do{\
    fprintf(stderr, "__%d__:", __LINE__); \
    perror(msg);\
}while(0)

#define PORT 8888               //端口号,范围1024~49151
#define IP  "192.168.114.85"    //本机IP,ifconfig

//需要传入到分支线程的参数
struct Climsg{
    int newfd;
    struct sockaddr_in cin;
};

void* deal_cli_msg(void* arg); //void* arg = (void*)&info




int main(int argc, const char *argv[])
{
    //创建流式套接字 socket
    int sfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sfd < 0)
    {
        ERR_MSG("socket");
        return -1;
    }
    printf("socket create success 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");


    //填充地址信息结构体给bind函数绑定,
    //真实的地址信息结构体根据地址族指定 AF_INET:man 7 ip
    struct sockaddr_in sin;
    sin.sin_family      = AF_INET;      //必须填AF_INET;
    sin.sin_port        = htons(PORT);  //端口号的网络字节序
    sin.sin_addr.s_addr = inet_addr(IP);//本机IP


    //绑定服务器的地址信息---> 必须绑定 bind
    if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
    {
        ERR_MSG("bind");
        return -1;
    }
    printf("bind success\n");


    //将套接字设置为被动监听状态 listen
    if(listen(sfd, 128) < 0)
    {
        ERR_MSG("listen");
        return -1;
    }
    printf("listen success\n");


    int newfd = -1;
    struct sockaddr_in cin;             //存储客户端的地址信息
    socklen_t addrlen = sizeof(cin);    //真实的地址信息结构体的大小
    pthread_t tid;
    struct Climsg info;

    while(1)
    {
        //主线程只负责连接
        //获取一个已经完成的客户端信息,生成一个新的文件描述符 accept
        //accept函数在阻塞的同时,会先预选一个newfd文件描述符,
        //当解除阻塞的时候,若该预选的newfd没有被使用的时候,直接返回该预选的文件描述符;
        //当解除阻塞的时候,若该预选的newfd已经被使用了,则需要重新遍历一个没有被使用的newfd返回
        newfd = accept(sfd, (struct sockaddr*)&cin, &addrlen);
        if(newfd < 0)
        {
            ERR_MSG("newfd");
            return -1;
        }
        printf("[%s:%d]客户端连接成功 newfd=%d\n", \
                inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);

        //能运行到当前位置,则代表有客户端连接成功,此时需要一个分支线程用于与客户端交互
        //分支线程只负责交互
        info.newfd = newfd;                                                                                                    
        info.cin = cin;
        if(pthread_create(&tid, NULL, deal_cli_msg, (void*)&info) != 0)
        {
            fprintf(stderr, "pthread_create failed __%d__\n", __LINE__);
            return -1;
        }

        //分离线程,分支线程退出后,由内核自动回收
        pthread_detach(tid);
    }


    //关闭文件名描述符
    if(close(sfd) < 0)
    {
        ERR_MSG("close");
        return -1;
    }

    return 0;
}


//线程执行体函数
void* deal_cli_msg(void* arg)   //void* arg = (void*)&info
{
    int newfd = ((struct Climsg*)arg)->newfd;
    struct sockaddr_in cin = ((struct Climsg*)arg)->cin;

    char buf[128] = "";
    ssize_t res = 0;
    while(1)
    {
        //清空字符串
        bzero(buf, sizeof(buf));    //memset

        //接收
        res = recv(newfd, buf, sizeof(buf), 0);
        if(res < 0)
        {
            ERR_MSG("recv");
            break;
        }
        else if(0 == res)
        {
            printf("[%s:%d]客户端下线 newfd=%d\n", \
                    inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);
            break;
        }
        printf("[%s:%d] newfd=%d : %s\n", \
                inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd, buf);

        //发送
        strcat(buf, "*_*");
        if(send(newfd, buf, sizeof(buf), 0) < 0)
        {
            ERR_MSG("send");
            break;
        }
        printf("send success\n");
    }

    close(newfd);

    pthread_exit(NULL);
}

3、思维导图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/950085.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【SpringSecurity】七、SpringSecurity集成thymeleaf

文章目录 1、thymeleaf2、依赖部分3、定义Controller4、创建静态页面5、WebSecurityConfigurerAdapter6、权限相关7、当用户没有某权限时&#xff0c;页面不展示该按钮 1、thymeleaf 查了下读音&#xff0c;leaf/li:f/&#xff0c;叶子&#xff0c;前面的单词发音和时间time一…

C++中的继承和派生

C 中的继承是类与类之间的关系&#xff0c;是一个很简单很直观的概念&#xff0c;与现实世界中的继承类似&#xff0c;例如儿子继承父亲的财产。 继承&#xff08;Inheritance&#xff09;可以理解为一个类从另一个类获取成员变量和成员函数的过程。例如类 B 继承于类 A&#x…

【SQL】关系模型与查询和更新数据

一、关系模型 1.1 主键 主键是关系表中记录的唯一标识。主键的选取非常重要&#xff1a;主键不要带有业务含义&#xff0c;而应该使用BIGINT自增或者GUID类型。主键也不应该允许NULL。 可以使用多个列作为联合主键&#xff0c;但联合主键并不常用。 1.2 外键 FOREIGN KEY …

Nginx详解之Nginx高级配置

Nginx详解之Nginx高级配置 1、网页的状态页2、Nginx第三方模块2.1echo模块 3、变量3.1内置变量3.2自定义变量 4、自定义访问日志4.1 自定义访问日志的格式4.2自定义json 格式日志 5、Nginx压缩功能&#xff08;重要&#xff09;6、https 功能6.1Nginx的HTTPS工作原理的详解6.2启…

【QT】信号和槽(15)

前面的内容说了很多不同的控件如何使用&#xff0c;今天来看下QT的核心&#xff0c;信号与槽&#xff08;Signals and slots&#xff09;&#xff01; 简单理解一下&#xff0c;就是我们的信号与槽连接上了之后&#xff0c;发射一个信号给到槽&#xff0c;槽函数接收到了这个信…

项目教程视频入口集合

题记&#xff1a;视频在b站&#xff0c;下面是入口 1.如何在gitlab创建项目 如何在gitlab创建项目_哔哩哔哩_bilibili如何在gitlab创建项目, 视频播放量 2、弹幕量 0、点赞数 0、投硬币枚数 0、收藏人数 0、转发人数 0, 视频作者 刘横川丶春秋, 作者简介 &#xff0c;相关视频…

XSS漏洞复现(CVE-2017-12794)

文章目录 搭建环境启动环境漏洞复现漏洞原理 前提条件&#xff1a; 1.安装docker docker pull medicean/vulapps:j_joomla_22.安装docker-compose docker run -d -p 8000:80 medicean/vulapps:j_joomla_23.下载vulhub 搭建环境 进入vulhb目录下的joomla&#xff0c;复现CVE-20…

半年营收下滑20%,阅文集团还有AI新故事?

新增长难寻&#xff0c;新故事难讲。阅文集团(下称“阅文”,00772.HK)承压的困局&#xff0c;都写在最新的半年报里。 8月10日&#xff0c;阅文交出侯晓楠接棒后的首份成绩单&#xff0c;尽管上半年阅文的净利有所扭转&#xff0c;但其营收持续下滑。 财报公布当天&#xff0…

结算日-洛谷

结算日 - 洛谷 解释&#xff1a; 1.用sum记录贝西走到某位置的累计的总钱&#xff0c;flag标记是否有欠债还不了的情况&#xff08;1为有&#xff09;&#xff0c;ans记录步数。 2.若sum<0&#xff0c;则欠债无法还&#xff0c;flag标记为1&#xff0c;并记录下此刻的位置…

Maven的profiles多环境配置

一个项目通常都会有多个不同的运行环境&#xff0c;例如开发环境&#xff0c;测试环境、生产环境等。而不同环境的构建过程很可能是不同的&#xff0c;例如数据源配置、插件、以及依赖的版本等。每次将项目部署到不同的环境时&#xff0c;都需要修改相应的配置&#xff0c;这样…

表观遗传学变异的西红柿

写在前面 最近在捣鼓表观遗传学&#xff0c;处理了一批Bulk RNA-Seq和WGBS(Whole Genome Bisulfite Sequencing)的数据。熟悉我风格的粉丝都知道&#xff0c;我一般会读几篇文献再下手&#xff0c;遂于PubMed中检索了几篇文章&#xff0c;发现一个2022年发表的题为"Compa…

1.8.6 练习 本科生学平均分绩点GPA计算(堆数组的应用)

C自学精简教程 目录(必读) 上大学要考试 我们读大学也要上课&#xff0c;上课也要考试的。 基本上每门课也都是满分100分。 虽然选择一个专业要上很多门课&#xff0c;每门课也都是100分&#xff0c;但是这些课程的“价值”却是不一样的。 有的课程是核心专业课&#xff1…

【python爬虫案例】用python爬豆瓣电影TOP250排行榜!

文章目录 一、爬虫对象-豆瓣电影TOP250二、python爬虫代码讲解三、同步视频四、获取完整源码 一、爬虫对象-豆瓣电影TOP250 前几天&#xff0c;我分享了一个python爬虫案例&#xff0c;爬取豆瓣读书TOP250数据&#xff1a;【python爬虫案例】用python爬豆瓣读书TOP250排行榜&a…

图像缩放、翻转、拼接的介绍与使用

目录 &#xff08;1&#xff09;图像缩放&#xff1a;resize() &#xff08;2&#xff09;图像翻转&#xff1a; flip() &#xff08;3&#xff09;图像拼接&#xff1a;hconcat() 和vconcat() &#xff08;1&#xff09;图像缩放&#xff1a;resize() 使用 cv2.resize() 函…

Next.js基础语法

Next.js 目录结构 入口App组件&#xff08;_app.tsx&#xff09; _app.tsx是项目的入口组件&#xff0c;主要作用&#xff1a; 可以扩展自定义的布局&#xff08;Layout&#xff09;引入全局的样式文件引入Redux状态管理引入主题组件等等全局监听客户端路由的切换 ts.config…

1.7 完善自定位ShellCode

在之前的文章中&#xff0c;我们实现了一个正向的匿名管道ShellCode后门&#xff0c;为了保证文章的简洁易懂并没有增加针对调用函数的动态定位功能&#xff0c;此类方法在更换系统后则由于地址变化导致我们的后门无法正常使用&#xff0c;接下来将实现通过PEB获取GetProcAddre…

手写RPC——数据序列化工具protobuf

手写RPC——数据序列化工具protobuf Protocol Buffers&#xff08;protobuf&#xff09;是一种用于结构化数据序列化的开源库和协议。下面是 protobuf 的一些优点和缺点&#xff1a; 优点&#xff1a; 高效的序列化和反序列化&#xff1a;protobuf 使用二进制编码&#xff0c…

QTableWidget实现鼠标悬停整行高亮显示

一、最终效果 二、 重写QTableWidget类 mytablewidget.h #ifndef MYTABLEWIDGET_H #define MYTABLEWIDGET_H#include <QTableWidget>class MyTableWidget : public QTableWidget { public:explicit MyTableWidget(QWidget* parent nullptr);protected:void leaveEve…

一页纸吃透PMP常考知识点!

我是胖圆~需要文档可留言 或者移步公众号【胖圆说PM】找我