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

桂林漓江介绍福建seo关键词优化外包

桂林漓江介绍,福建seo关键词优化外包,wordpress 宽屏主题,上海南京路万人抗议一 . 只能被一个client 链接 socket例子 此例子用于socket 例子, 该例子只能用于一个客户端连接server。 不能用于多个client 连接 server socket_server_support_one_clientconnect.c /* 此例子用于socket 例子, 该例子只能用于一个客户端连接server。…

一 . 只能被一个client 链接 socket例子

此例子用于socket 例子,
该例子只能用于一个客户端连接server。
不能用于多个client 连接  server

socket_server_support_one_clientconnect.c


/*
此例子用于socket 例子,
该例子只能用于一个客户端连接server。
不能用于多个client 连接  server*/
#include "wrap.h"
#define SERVER_PORT 8888int main(int argc, const char* argv[]) {int lfd;// 第一步:创建 lfdlfd = Socket(AF_INET, SOCK_STREAM, 0);// 第二步: 给lfd 绑定 IP 和 PORT,这里需要将 port 和IP 从小端转成大端struct sockaddr_in sockaddrin_server;sockaddrin_server.sin_family = AF_INET;sockaddrin_server.sin_port = htons(SERVER_PORT);sockaddrin_server.sin_addr.s_addr = htonl(INADDR_ANY);Bind(lfd,(struct sockaddr *)&sockaddrin_server,sizeof(sockaddrin_server));//第三步:设定监听上限,这个监听上限的意思是:同时只能有8个客户端和此 server连接,我们这个server只能要一个客户端和我们连接,因此这个值在这里没有具体意义Listen(lfd, 8);// 第四步 :阻塞,并等待客户端连接. accept的第二个参数是传入传出参数,代表的是:成功于服务器连接的客户端的 地址结构struct sockaddr_in sockaddrin_client;socklen_t sockaddrin_clientsocklen_t = sizeof(sockaddrin_client);int  cfd = Accept(lfd, (struct sockaddr *)&sockaddrin_client, &sockaddrin_clientsocklen_t);char clientip[33] = { 0 };const char* clientipresult = inet_ntop(AF_INET, &sockaddrin_client.sin_addr.s_addr, clientip, 32);if (clientipresult == NULL) {printf("inet_ntop error\n");}else {printf("client addr port = %d,addr ip = %s \n", ntohs(sockaddrin_client.sin_port), clientipresult);}printf("client addr port = %d,addr ip = %s \n",ntohs(sockaddrin_client.sin_port), clientip);//只要客户端连接上了, 没有错误,就会走到这一步。//第五步:连接上后,server端就可以循环的 使用read函数 读取客户端发送过来的数据了。//注意的是,read函数默认是阻塞读取的char readbuffer[256] = { 0 };int readbufferlen = 0;while (1) {readbufferlen = Read(cfd, readbuffer, 256);printf("read buffer from client %s \n", readbuffer);for (int i = 0; i < readbufferlen; ++i) {readbuffer[i] = toupper(readbuffer[i]);}Write(cfd, readbuffer, readbufferlen);Write(STDOUT_FILENO, readbuffer, readbufferlen);}
}

wrap.h

#ifndef __WRAP_H_
#define __WRAP_H_#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
#include <netinet/ip.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);
static 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 "wrap.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;
}/*参三: 应该读取的字节数*/
ssize_t Readn(int fd, void* vptr, size_t n)
{size_t  nleft;              //usigned int 剩余未读取的字节数ssize_t nread;              //int 实际读到的字节数char* ptr;ptr = vptr;nleft = n;while (nleft > 0) {if ((nread = read(fd, ptr, nleft)) < 0) {if (errno == EINTR)nread = 0;elsereturn -1;}else if (nread == 0)break;nleft -= nread;ptr += nread;}return n - nleft;
}ssize_t Writen(int fd, const void* vptr, size_t n)
{size_t nleft;ssize_t nwritten;const char* ptr;ptr = vptr;nleft = n;while (nleft > 0) {if ((nwritten = write(fd, ptr, nleft)) <= 0) {if (nwritten < 0 && errno == EINTR)nwritten = 0;elsereturn -1;}nleft -= nwritten;ptr += nwritten;}return n;
}static ssize_t my_read(int fd, char* ptr)
{static int read_cnt;static char* read_ptr;static char read_buf[100];if (read_cnt <= 0) {again:if ((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {if (errno == EINTR)goto again;return -1;}else if (read_cnt == 0)return 0;read_ptr = read_buf;}read_cnt--;*ptr = *read_ptr++;return 1;
}ssize_t Readline(int fd, void* vptr, size_t maxlen)
{ssize_t n, rc;char    c, * ptr;ptr = vptr;for (n = 1; n < maxlen; n++) {if ((rc = my_read(fd, &c)) == 1) {*ptr++ = c;if (c == '\n')break;}else if (rc == 0) {*ptr = 0;return n - 1;}elsereturn -1;}*ptr = 0;return n;
}int tcp4bind(short port, const char* IP)
{struct sockaddr_in serv_addr;int lfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&serv_addr, sizeof(serv_addr));if (IP == NULL) {//如果这样使用 0.0.0.0,任意ip将可以连接serv_addr.sin_addr.s_addr = INADDR_ANY;}else {if (inet_pton(AF_INET, IP, &serv_addr.sin_addr.s_addr) <= 0) {perror(IP);//转换失败exit(1);}}serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(port);//端口复用代码,在bind之前int opt = 1;setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));Bind(lfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));return lfd;
}

编译命令

gcc socket_server_support_one_clientconnect.c wrap.c -o socket_server_support_one_clientconnect.out
这里使用的是 gcc build, 如果使用g++,则会有build error,因为g++的语法检查,要比 gcc 严格一些。
error 信息如下g++ socket_server_support_one_clientconnect.c wrap.c -o socket_server_support_one_clientconnect.out
wrap.c: In function ‘ssize_t Readn(int, void*, size_t)’:
wrap.c:111:8: error: invalid conversion from ‘void*’ to ‘char*’ [-fpermissive]ptr = vptr;^~~~
wrap.c: In function ‘ssize_t Writen(int, const void*, size_t)’:
wrap.c:136:8: error: invalid conversion from ‘const void*’ to ‘const char*’ [-fpermissive]ptr = vptr;^~~~
wrap.c: In function ‘ssize_t Readline(int, void*, size_t)’:
wrap.c:180:8: error: invalid conversion from ‘void*’ to ‘char*’ [-fpermissive]ptr = vptr;

二 . 可以被多个 client 链接 socket 例子,使用 父子进程完成。

2.1 添加 将 SIGCHLD 信号屏蔽

    //信号屏蔽是指进程主动阻止某些信号的递达,直到屏蔽解除,被屏蔽的信号在屏蔽期间仍然会产生,但不会被处理,直到屏蔽解除后才会被处理,信号屏蔽通常用于保护临界区代码,防止信号处理程序与普通代码同时执行导致的数据不一致问题。
 

            sigset_t set;
            sigemptyset(&set);
            sigaddset(&set, SIGCHLD);
            sigprocmask(SIG_BLOCK, &set, NULL);

2.2 端口复用

        server IP 和 port可以复用

        setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
 

2.3 父进程完成的任务有:

        2.3.1.负责监听lfd功能.因此先要关闭 cfd

        2.3.2 父进程还需要回收子进程,以避免子进程完成后变成僵尸进程

                sigaction 在windows 上使用vs2019 编写linux代码,即使添加了#include <signal.h>,也无法识别,原因未知,但是在 linux环境下 build 是可以pass 的。

                            struct sigaction act;
                            act.sa_handler = catchchild;
                            sigemptyset(&act.sa_mask);
                            act.sa_flags = 0;
                            sigaction(SIGCHLD, &act, NULL);

        2.3.3 屏蔽解除 sigprocmask(SIG_UNBLOCK, &set, NULL);

2.4 子进程完成的任务有:

        2.4.1 子进程,负责 cfd 和 client的交换数据发送信息功能。因此先要关闭 lfd

                close(lfd);

        2.4.2 连接上后,循环的 使用read函数 读取客户端发送过来的数据了。注意的是,read函数默认是阻塞读取的
 

            char readbuffer[256] = { 0 };
            int readbufferlen = 0;

            while (1) {
                readbufferlen = Read(cfd, readbuffer, 256);
                printf("read buffer from client %s \n", readbuffer);
                for (int i = 0; i < readbufferlen; ++i) {
                    readbuffer[i] = toupper(readbuffer[i]);
                }
                Write(cfd, readbuffer, readbufferlen);
                Write(STDOUT_FILENO, readbuffer, readbufferlen);
            }

2.5 完整代码:

socket_server_support_more_clientconnect_use_fork.c


/*
此例子用于socket 例子,
该例子只能用于多个客户端连接server。基于 父子进程 实现
父进程 用于 lfd ,
子进程 用于 cfd.测试的问题1: listen(lfd,num) 监听的上限数量问题。*/
#include "wrap.h"
#define SERVER_PORT 8888void catchchild(int single) {pid_t pid;int status;while (1) {pid = waitpid(-1, &status, WNOHANG);if (pid <=0 ) {break;}else if (pid > 0) {printf("child pid = %\d exit \n",pid);if (WIFEXITED(status)) {//WIFEXITED(status)为真,说明是子线程是正常结束的。。使用WEXITSTATUS(status)  ---  获取进程退出状态 (exit的参数)printf("child normal die ,die information : %d \n", WEXITSTATUS(status));}if (WIFSIGNALED(status)) {//WIFSIGNALED(status)为真,说明子线程异常终止。。使用WTERMSIG(status) --- 取得使进程终止的那个信号的编号printf("child not normal die ,die information : %d \n", WTERMSIG(status));}}}
}int main(int argc, const char* argv[]) {//第零步:将 SIGCHLD 信号屏蔽,这样做的原因是,有可能当父进程还没有 注册 完成 SIGCHID 的时候,子进程已经执行完毕了,因此在main 函数的最前面,将信号屏蔽了//信号屏蔽是指进程主动阻止某些信号的递达,直到屏蔽解除,被屏蔽的信号在屏蔽期间仍然会产生,但不会被处理,直到屏蔽解除后才会被处理,信号屏蔽通常用于保护临界区代码,防止信号处理程序与普通代码同时执行导致的数据不一致问题。sigset_t set;sigemptyset(&set);sigaddset(&set, SIGCHLD);sigprocmask(SIG_BLOCK, &set, NULL);int lfd;// 第一步:创建 lfdlfd = Socket(AF_INET, SOCK_STREAM, 0);// 第一步 让 server IP 和 port可以复用。int opt = 1;setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));// 第二步: 给lfd 绑定 IP 和 PORT,这里需要将 port 和IP 从小端转成大端struct sockaddr_in sockaddrin_server;sockaddrin_server.sin_family = AF_INET;sockaddrin_server.sin_port = htons(SERVER_PORT);sockaddrin_server.sin_addr.s_addr = htonl(INADDR_ANY);Bind(lfd, (struct sockaddr*)&sockaddrin_server, sizeof(sockaddrin_server));//第三步:设定监听上限,这个监听上限的意思是:同时只能有2个客户端和此 server连接,我们这个server只能要2个客户端和我们连接,测试如果有3个的客户端连接的情况下,server端发生的现象 和 client端发生的现象,因此还需要写一个客户端Listen(lfd, 2);// 第四步 :accept 阻塞监听客户端连接,并 fork出子进程。// 4.1 阻塞,并等待客户端连接. accept的第二个参数是传入传出参数,代表的是:成功于服务器连接的客户端的 地址结构struct sockaddr_in sockaddrin_client;socklen_t sockaddrin_clientsocklen_t = sizeof(sockaddrin_client);pid_t pid;while (1) {int  cfd = Accept(lfd, (struct sockaddr*)&sockaddrin_client, &sockaddrin_clientsocklen_t);char clientip[33] = { 0 };const char* clientipresult = inet_ntop(AF_INET, &sockaddrin_client.sin_addr.s_addr, clientip, 32);if (clientipresult == NULL) {printf("inet_ntop error\n");}else {printf("client addr port = %d,addr ip = %s \n", ntohs(sockaddrin_client.sin_port), clientipresult);}pid = fork();if (pid == -1) {//fork 函数的 error 处理perr_exit("fork error");}else if (pid > 0) {//4.1 父进程,负责监听lfd功能.因此先要关闭 cfdclose(cfd);//4.2 父进程还需要回收子进程,以避免子进程完成后变成僵尸进程。// 那么如何回收呢? 如果是 阻塞回收,那么while(1)的循环在父进程这里就卡在这里了// 如果是 不阻塞忙轮询 回收呢?也不行,怎么忙轮询呢?// 因此这里只能用信号捕捉函数 ,捕捉 SIGCHID 信号//struct sigaction {//	void     (*sa_handler)(int);//	void     (*sa_sigaction)(int, siginfo_t*, void*);//	sigset_t   sa_mask;//	int        sa_flags;//	void     (*sa_restorer)(void);//};//int sigaction(int signum, const struct sigaction* act,struct sigaction* oldact);struct sigaction act;act.sa_handler = catchchild;sigemptyset(&act.sa_mask);act.sa_flags = 0;sigaction(SIGCHLD, &act, NULL);//4.3 屏蔽解除sigprocmask(SIG_UNBLOCK, &set, NULL);}else if (pid == 0 ) {//4.4 子进程,负责 cfd 和 client的交换数据发送信息功能。因此先要关闭 lfdclose(lfd);//4.5 连接上后,循环的 使用read函数 读取客户端发送过来的数据了。注意的是,read函数默认是阻塞读取的char readbuffer[256] = { 0 };int readbufferlen = 0;while (1) {readbufferlen = Read(cfd, readbuffer, 256);printf("read buffer from client %s \n", readbuffer);for (int i = 0; i < readbufferlen; ++i) {readbuffer[i] = toupper(readbuffer[i]);}Write(cfd, readbuffer, readbufferlen);Write(STDOUT_FILENO, readbuffer, readbufferlen);}}}
}

2.6 编译命令

gcc wrap.c socket_server_support_more_clientconnect_use_fork.c -o socket_server_support_more_clientconnect_use_fork.out

*****关于 listen 第二个参数的 问题研究

在代码中,设定的listen(lfd,2); 那么这个参数2刚开始的自己的想法是:最多有两个客户端连接上server,但是实际测试中,用了5客户端连接,都没有问题,这说明啥呢?说明自己对 listen的第二个参数理解是不对的。
 

listen(lfd,2); 这个listen的第二个参数是啥意思呢?赋值多少比较合理呢?

我们先来看 listen参数的说明:

       The backlog argument defines the maximum length to which the  queue  of
       pending  connections  for  sockfd  may  grow.   If a connection request
       arrives when the queue is full, the client may receive an error with an
       indication  of  ECONNREFUSED  or,  if  the underlying protocol supports
       retransmission, the request may be ignored so that a later reattempt at
       connection succeeds.

  backlog :就是你设置的参数值

中文翻译就是:

backlog 参数定义了待处理连接队列的最大长度,sockfd 可能会增长。如果连接请求在队列已满时到达,客户端可能会收到带有 ECONNREFUSED 指示的错误,或者如果底层协议支持重传,该请求可能会被忽略,以便稍后重新尝试连接成功。

这两个博客说的很仔细:

https://zhuanlan.zhihu.com/p/634606981

listen()函数的第二个参数详解_listen函数的第二个参数-CSDN博客

整理核心:所以,backlog 目前的真正含义就是:

(1)在linux 2.2 内核之前,backlog是指半连接队列(syns_queue)的长度。

(2)在linux2.2及之后,backlog是指已经完全建立连接,但是还没有被应用层accept之前,socket所处全连接队列(accetp_queue)的长度。

全连接队列是什么?

全连接队列存储3次握手成功并已建立的连接,将其称为全连接队列,也可称为接收队列(Accept队列),本文中的描述将称为Accept队列或全连接队列。如下红框中所示,全连已成功建立三次握手,当前的TCP状态为ESTABLISHED,但是服务端还未Accept的队列。

要核心学习这,实际上要学习linux 内核的整体课程才能有深入的了解,这里只是对这个知识点比较迷惑,记录一下。

三. 可以被多个 client 链接 socket 例子,使用 子线程完成

socket_server_support_more_clientconnect_use_pthread.c

/*
使用线程完成 socket 并发服务器
主线程socket,bind ,listen,
在循环中,accept得到 cfd ,并创建 pthread,在pthread函数中 */#include "wrap.h"
#include <pthread.h>typedef struct c_info
{int cfd;struct sockaddr_in cliaddr;}CINFO;void* client_fun(void* arg);int main(int argc, char* argv[]) {//当 pthread_attr_t 是全局变量的时候,可以直接使用静态方式初始化,目的是 设置pthread的属性为 分离pthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);short port = 8888;int lfd = tcp4bind(port, NULL);//创建套接字 绑定 Listen(lfd, 128);struct sockaddr_in cliaddr;socklen_t len = sizeof(cliaddr);CINFO* info;while (1){int cfd = Accept(lfd, (struct sockaddr*)&cliaddr, &len);char ip[16] = "";pthread_t pthid;//将accpet后的 cfd 做为参数传递到 子线程。info = malloc(sizeof(CINFO));info->cfd = cfd;info->cliaddr = cliaddr;//在前面已经将 attr 设置为分离态了,因此不存在 主线程回收的问题pthread_create(&pthid, &attr, client_fun, info);}return 0;}//子线程启动调用函数
void* client_fun(void* arg)
{CINFO* info = (CINFO*)arg;char ip[16] = "";printf("new client ip=%s port=%d\n", inet_ntop(AF_INET, &(info->cliaddr.sin_addr.s_addr), ip, 16),ntohs(info->cliaddr.sin_port));while (1){char buf[1024] = "";int count = 0;count = read(info->cfd, buf, sizeof(buf));if (count < 0){perror("");break;}else if (count == 0){printf("client close\n");break;}else{printf("%s\n", buf);write(info->cfd, buf, count);}}close(info->cfd);//记得最后要释放info,避免内存泄漏free(info);
}

编译命令

gcc wrap.c socket_server_support_more_clientconnect_use_pthread.c -lpthread -o socket_server_support_more_clientconnect_use_pthread.out

四. select 模型

五 poll 模型

六 epoll 模型

http://www.hkea.cn/news/76786/

相关文章:

  • linux做网站服务器吗关键词上首页软件
  • 西安网站建设行业动态手机营销软件
  • 做推送的网站推荐今日新闻摘抄50字
  • 想在自己的网站做支付优化公司治理结构
  • 国内一家做国外酒店团购的网站网络推广优化是干啥的
  • 手机3d动画制作软件重庆网络seo公司
  • 青海和城乡建设厅网站石家庄自动seo
  • 建站网址是多少深圳市seo上词多少钱
  • 应用网站开发创建网站花钱吗
  • 2023太原疫情优化设计答案大全
  • 创新的专业网站建设适合小学生的新闻事件
  • 政府机关备案网站百度竞价什么意思
  • 广元专业高端网站建设seo视频
  • 烟台网站建设诚信臻动传媒百度网络营销中心
  • 贵阳网站建设搜王道下拉重庆seo网络推广关键词
  • 大型 网站的建设 阶段百度官方网站下载
  • 江苏专业做网站的公司百度地图导航网页版
  • 怎么去投诉做网站的公司宁波seo外包推广软件
  • 网络营销跟做网站有什么区别线上推广如何引流
  • 如何进行网店推广seo排名优化怎样
  • 什么建站程序好收录上海网络公司seo
  • 电子商务网站建设投资预算小程序平台
  • 广州外贸营销型网站成都移动seo
  • 如何韩国视频网站模板下载 迅雷下载sem竞价托管费用
  • 做网站去哪个平台seo培训学院
  • 网站移动端优化的重点有哪些营销策略ppt
  • 养车网站开发搜狗seo快速排名公司
  • 企业电子商务网站建设武汉百度快速排名提升
  • 建一个网站的流程今天刚刚发生的新闻
  • 建立网站请示优化服务是什么意思