当前位置: 首页 > news >正文

做word文档什么网站好北京有哪些网站制作公司

做word文档什么网站好,北京有哪些网站制作公司,南通网站建设培训,设计师交流平台有哪些常见的socket函数封装和多进程和多线程实现服务器并发 1.常见的socket函数封装2.多进程和多线程实现服务器的并发2.1多进程服务器2.2多线程服务器2.3运行效果 1.常见的socket函数封装 accept函数或者read函数是阻塞函数,会被信号打断,我们不能让它停止&a…

常见的socket函数封装和多进程和多线程实现服务器并发

  • 1.常见的socket函数封装
  • 2.多进程和多线程实现服务器的并发
    • 2.1多进程服务器
    • 2.2多线程服务器
    • 2.3运行效果

1.常见的socket函数封装

在这里插入图片描述

accept函数或者read函数是阻塞函数,会被信号打断,我们不能让它停止,所以我们应该进行一些封装操作。

//wrap.h#ifndef __WRAP_H_
#define __WRAP_H_
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <strings.h>void perr_exit(const char *s);
int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr);
int Bind(int fd, const struct sockaddr *sa, socklen_t salen);
int Connect(int fd, const struct sockaddr *sa, socklen_t salen);
int Listen(int fd, int backlog);
int Socket(int family, int type, int protocol);
ssize_t Read(int fd, void *ptr, size_t nbytes);
ssize_t Write(int fd, const void *ptr, size_t nbytes);
int Close(int fd);
ssize_t Readn(int fd, void *vptr, size_t n);
ssize_t Writen(int fd, const void *vptr, size_t n);
ssize_t my_read(int fd, char *ptr);
ssize_t Readline(int fd, void *vptr, size_t maxlen);
int tcp4bind(short port,const char *IP);
#endif

下面是相关函数的实现

//wrap.c#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <strings.h>void perr_exit(const char *s)
{perror(s);exit(-1);
}int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{int n;again:if ((n = accept(fd, sa, salenptr)) < 0) {if ((errno == ECONNABORTED) || (errno == EINTR))goto again;elseperr_exit("accept error");     }return n;
}int Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{int n;if ((n = bind(fd, sa, salen)) < 0)perr_exit("bind error");return n;
}int Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{int n;if ((n = connect(fd, sa, salen)) < 0)perr_exit("connect error");return n;
}int Listen(int fd, int backlog)
{int n;if ((n = listen(fd, backlog)) < 0)perr_exit("listen error");return n;
}int Socket(int family, int type, int protocol)
{int n;if ((n = socket(family, type, protocol)) < 0)perr_exit("socket error");return n;
}ssize_t Read(int fd, void *ptr, size_t nbytes)
{ssize_t n;again:if ( (n = read(fd, ptr, nbytes)) == -1) {if (errno == EINTR)goto again;elsereturn -1;}return n;
}ssize_t Write(int fd, const void *ptr, size_t nbytes)
{ssize_t n;again:if ( (n = write(fd, ptr, nbytes)) == -1) {if (errno == EINTR)goto again;elsereturn -1;}return n;
}int Close(int fd)
{int n;if ((n = close(fd)) == -1)perr_exit("close error");return n;
}

2.多进程和多线程实现服务器的并发

当有多个客户端向服务器发送数据的时候,我们如何去操作,这就涉及到了我们的多线程和多进程开发了,下面看看如何来实现。

2.1多进程服务器

(1)首先我们想如何通过多进程来实现呢?那么我们得想清楚父子进程分别来干啥,我们可以这样,父进程来获取连接

(2)然后子进程来进行通信发送数据给服务端。

(3)最后我们利用信号的方式来回收子进程,防止出现僵尸进程。

/*多进程实现并发,主进程中使用sigaction函数回收子进程*/
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include "wrap.h"void sighandler(int sig)
{pid_t wpid;//回收子进程while(1){wpid = waitpid(-1, NULL, WNOHANG);if(wpid <= 0){break;}}
}int main()
{int lfd = Socket(AF_INET, SOCK_STREAM, 0);//设置端口复用int opt = 1;setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));struct sockaddr_in serverAddr;bzero(&serverAddr, sizeof(serverAddr));serverAddr.sin_family = AF_INET;serverAddr.sin_port = htons(8888);serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);Bind(lfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));Listen(lfd, 128);//将SIGCHLD信号阻塞sigset_t mask;sigemptyset(&mask);sigaddset(&mask, SIGCHLD);sigprocmask(SIG_BLOCK, &mask, NULL);int cfd;pid_t mpid;struct sockaddr_in clientAddr;socklen_t len = sizeof(clientAddr);while(1){cfd = Accept(lfd, (struct sockaddr*)&clientAddr, &len);mpid = fork();if (mpid < 0){perror("fork error:");exit(0);}else if (mpid > 0){close(cfd);//signal(SIGCHLD, sighandler);//注册信号处理函数struct sigaction act;act.sa_handler = sighandler;sigemptyset(&act.sa_mask);act.sa_flags = 0;sigaction(SIGCHLD, &act, NULL);//解除对SIGCHLD信号的阻塞sigprocmask(SIG_UNBLOCK, &mask, NULL);}else if(mpid == 0){//子进程中执行消息收发close(lfd);char buf[1024];int nLen; char cIP[16];while(1){memset(buf, 0, sizeof(buf));nLen = Read(cfd, buf, sizeof(buf));if (nLen <= 0){perror("read error:");break;}printf("%s--%d: %s\n", inet_ntop(AF_INET, &clientAddr.sin_addr.s_addr, cIP, sizeof(cIP)), ntohs(clientAddr.sin_port), buf);strcat(buf, "---recvied");Write(cfd, buf, strlen(buf));}close(cfd);exit(0);  //子进程退出,防止子进程继续创建子进程}}close(lfd);return 0;
}

2.2多线程服务器

接下来就是多线程服务器如何去实现呢?

我们可以参考上面的多进程开发:
(1)首先我们利用主进程来获取连接。

(2)然后利用子线程来和服务器进行通信给服务器发送数据。

(3)最后设置线程分离属性,任务完成后自动回收子线程。

注意:

(1)线程和进程之间是有不同的,线程的文件描述符时共享的,一旦有一个新的连接过来的时候,所有的通信文件描述符cfd都会改变,但是进程时写时拷贝的,所以进程不会出现这种情况。因此在使用线程开发时,我们要分别给他们开辟空间,这里可以用一个结构体,不同线程使用不同的空间

(2)由于线程的文件描述符是共享的,所以我们不可以关闭父线程的通信文件描述符,这样会导致子线程的通信文件描述符全关闭,导致子线程无法正常通信;而进程程会有计数引用,只会是通信文件描述符的引用次数减1,不会直接全部关闭。

下面是代码:

/*多线程实现并发, 解决多个子线程共享cfd存在的问题*/
#include "wrap.h"
#include <pthread.h>#define MAX_NUM 100struct PthreadInfo
{int cfd;  //若为-1表示可用, 大于0表示已被占用pthread_t threadID;struct sockaddr_in clientAddr;
};
//定义结构体数组,不同的线程访问不同的内存
struct PthreadInfo info[MAX_NUM];//线程执行函数
void* mythread(void* arg)
{struct PthreadInfo* p = (struct PthreadInfo*)arg;char buf[1024];int cfd = p->cfd;ssize_t len;while (1){memset(buf, 0, sizeof(buf));len = Read(cfd, buf, sizeof(buf));if (len <= 0){perror("read error:");close(cfd);p->cfd = -1;  //设置为-1表示该位置可用pthread_exit(NULL);}printf("%s\n", buf);strcat(buf, "---recvied");Write(cfd, buf, strlen(buf));}}void init_info()
{//初始化数组,当cfd = -1时表明这块内存空间可以使用for (size_t i = 0; i < MAX_NUM; i++){info[i].cfd = -1;}
}int find_index()
{int i;for(i = 0; i < MAX_NUM; i++){if (info[i].cfd == -1){break;}}if (i == MAX_NUM){return -1;}return i;
}int main()
{int lfd = Socket(AF_INET, SOCK_STREAM, 0);//设置端口复用int opt = 1;setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));struct sockaddr_in serverAddr;bzero(&serverAddr, sizeof(serverAddr));serverAddr.sin_family = AF_INET;serverAddr.sin_port = htons(8888);serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);Bind(lfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));Listen(lfd, 128);//初始化init_info();int cfd;int ret;int idx;socklen_t len;struct sockaddr_in client;while (1){len = sizeof(client);bzero(&client, len);cfd = Accept(lfd, (struct sockaddr*)&client, &len);//找数组中空闲的位置idx = find_index();if (idx == -1){close(cfd);continue;}//对空闲位置的元素的成员赋值info[idx].cfd = cfd;memset(&info[idx].clientAddr, &client, len);//创建子线程---该子线程完成对数据的收发ret = pthread_create(&info[idx].threadID, NULL, mythread, &info[idx]);if(ret!=0){printf("create thread error:[%s]\n", strerror(ret));exit(-1);}//设置子线程为分离属性pthread_detach(info[idx].threadID);}close(lfd);return 0;
}

我们在写的时候发现当一些进程完成通信以后,关闭文件描述符,我们的空间是无法进行回收的,这样就会大大浪费空间,因此我们可以写一个函数来返回结束通信的空间位置可利用的空间,来使用这块空间。

int find_index()
{int i;for(i = 0; i < MAX_NUM; i++){if (info[i].cfd == -1){break;}}if (i == MAX_NUM){return -1;}return i;
}

2.3运行效果

下面我们看看效果

1.这是连接的第一个客户端,可以看到通信正常
在这里插入图片描述
2.这是连接的第二个客户端,通信也正常

在这里插入图片描述3.我们用命令来看看连接的状态

在这里插入图片描述
可以看到tcp连接是一个双向的可靠连接,我们连接了两个客户端,所以有四个连接,可以看到都处于ESTABLISHESD的状态,可以看出是达到了效果。两个客户端和服务端的通信都是正常的。

http://www.yayakq.cn/news/824729/

相关文章:

  • 招聘网站开发费用wordpress添加logo
  • 附近旅游团地址电话怎么搜索徐州seo推广优化
  • 在中国备案的网站服务器怎样网站不用备案
  • 沈阳市城乡建设网站在线定制英文名
  • 免费正能量网站下载ww企业数字化平台
  • wordpress可以做电影站asp网站伪静态
  • 如何做印刷报价网站无锡万度网站建设
  • 织梦移动端网站模板下载地址专门制作网站
  • 西宁做网站的网络公司如何做电影网站资源
  • 株洲网站建设报价网站建设合优
  • 大学生兼职网站的融资方案正方教务系统管理系统入口
  • 建设公司网站费用腾讯企业邮箱电脑版登录入口
  • 怎么用网站做地标wordpress搭建学校网站
  • 域名手机网站源码公司品牌策划设计
  • 建设网站的体会如何建设网站济南兴田德润团队怎么样
  • 安溪网站制作什么是互联网
  • 怎做连接网站wordpress 代替
  • pc站转换手机网站建设营销网站的四个步骤
  • 博物馆网站模版想做电商网站运营要怎么做
  • 昆明制作手机网站网易企业邮箱手机登录
  • 网站分类页标题加长南宁seo标准
  • 梅州建站网络科技有限公司php做网站项目的思路
  • 苏州网站建设网络做暧昧在线网站
  • 张掖市网站建设wordpress首页分页代码
  • 简述建设网站的具体步骤wordpress默认后台登陆
  • 产品网站建设多少钱郑州企业管理咨询有限公司
  • 网站ftp地址查询wordpress 熊掌
  • 专业点的网站制作公司快站优惠券去哪里找
  • 手机网站建立教程三种人不易感染新冠
  • 内蒙古呼和浩特景点整站优化seo