服务器网站源码在哪自己开发微信小程序教程
- 作者: 五速梦信息网
- 时间: 2026年03月21日 11:15
当前位置: 首页 > news >正文
服务器网站源码在哪,自己开发微信小程序教程,网站后台内容编辑器下载,个人网站的设计师一 . 只能被一个client 链接 socket例子 此例子用于socket 例子#xff0c; 该例子只能用于一个客户端连接server。 不能用于多个client 连接 server socket_server_support_one_clientconnect.c /* 此例子用于socket 例子#xff0c; 该例子只能用于一个客户端连接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 __WRAPH #define __WRAPH#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.hvoid 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);#endifwrap.c #include wrap.hvoid 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(lfd2); 那么这个参数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 并发服务器 主线程socketbind listen 在循环中accept得到 cfd 并创建 pthread在pthread函数中 /#include wrap.h #include pthread.htypedef 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 模型
- 上一篇: 服务器网站网站专用无锡做装修网站
- 下一篇: 服务器做两个网站网站建设三网合一是什么
相关文章
-
服务器网站网站专用无锡做装修网站
服务器网站网站专用无锡做装修网站
- 技术栈
- 2026年03月21日
-
服务器网站目录拓者吧室内设计网官网
服务器网站目录拓者吧室内设计网官网
- 技术栈
- 2026年03月21日
-
服务器网站建设维护中国建设银行官网首页登录入口
服务器网站建设维护中国建设银行官网首页登录入口
- 技术栈
- 2026年03月21日
-
服务器做两个网站网站建设三网合一是什么
服务器做两个网站网站建设三网合一是什么
- 技术栈
- 2026年03月21日
-
服务器做网站配置网业分离
服务器做网站配置网业分离
- 技术栈
- 2026年03月21日
-
服务推广软文seo应该怎么做
服务推广软文seo应该怎么做
- 技术栈
- 2026年03月21日






