linux网络编程实战

前言

        之前找工作的之后写了一些网络编程的笔记和代码,然后现在放到csdn上保存一下。有几个版本的,看看就好。就是简单的实现一下服务端和客户端之间的交互的,还没有我之前上linux编程课写的代码复杂。

        哦对了,这个网络编程的代码对错误处理函数进行了一些封装,就是将select、accept等函数进一步封装了一下,问题不大。要是有朋友看到这篇博客想学习啥的,有问题可以问我。这个其实是在b站上看视频写的代码,嗯,其实没必要看我的代码的。

        最后,客户端的代码都是一样的,不用客户端的代码其实也可以,启动服务端后直接用nc命令进行测试就行。

makefile文件

        这个makefile文件都是通用的。客户端自行将server改为client就可以。-pthread在不用多线程的时候可以删掉。

CXX = gcc
OBJS = server.o wrap.o 
TARGET = server
$(TARGET):$(OBJS)$(CXX) $^ -o $@ -pthread
$*.o:$%.c$(CXX) -c $< -o $@
.PHONY: clean
clean:rm -rf $(OBJS) $(TARGET) 

错误处理函数封装头文件wrap.h

#ifndef __WRAP_H_
#define __WRAP_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);
#endif

错误处理函数封装wrap.c:

#include <stdlib.h>
#include <errno.h>
#include <sys/socket.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;ssize_t nread;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;
}

客户端代码client.c

#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "wrap.h"#define SERVER_PORT 8888 //需要与服务器相同int main(int argc, char *argv[])
{int sc=0,err=0,slen=0;char message[1024]={0};struct sockaddr_in server_addr;bzero(&server_addr,sizeof(server_addr));server_addr.sin_family=AF_INET;server_addr.sin_port=htons(SERVER_PORT);server_addr.sin_addr.s_addr=htonl(INADDR_ANY);//或inet_pton(AF_INET,"127.0.0.1",&server_addr.sin_addr.s_addr);sc=Socket(AF_INET,SOCK_STREAM,0);err = Connect(sc,(struct sockaddr*)&server_addr,sizeof(struct sockaddr));while(1){//持续进行通信slen=Read(0,message,sizeof(message));slen=Write(sc,message,slen);slen=Read(sc,message,slen);slen=Write(1,message,slen);}Close(sc);return 0;
}

第一版服务器(直接发送接受,只能一次且一个客户端)

        服务器的代码文件名称均为server.c

#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "wrap.h"//宏定义
#define MAXLEN 100  //设置监听上限
#define SERVER_PORT 8888  //绑定的端口int main(int argc, char *argv[])
{int ss=0,sc=0,slen=0,err=0;//创建套接字char message[1024]={0},client_ip[1024]={0};//创建字符串来作为缓冲区,或用BUFSIZ=4096struct sockaddr_in server_addr,client_addr;//创建服务器端和客户端的地址结构socklen_t addrlen;//地址结构的长度bzero(&server_addr,sizeof server_addr);//清零server_addr.sin_family = AF_INET;//协议族server_addr.sin_port = htons(SERVER_PORT);//绑定端口server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//绑定IPss = Socket(AF_INET,SOCK_STREAM,0);int opt=1;setsockopt(ss,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));//设置端口复用err = Bind(ss,(struct sockaddr*)&server_addr,sizeof server_addr);//给socket绑定地址结构err = Listen(ss,MAXLEN);//设置监听上限addrlen = sizeof(struct sockaddr);sc=Accept(ss,(struct sockaddr*)&client_addr,&addrlen);printf("client ip:%s,port:%d\n",inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,client_ip,sizeof(client_ip)),ntohs(client_addr.sin_port));//inet_ntop:将网络字节序转为本地字节序//ntohs:将网络端口转为本地端口while(1){slen = Read(sc,message,1024);//接收信息Write(1,message,slen);//将收到的信息输出,STDOUT_FILENO=1,STDIN_FILENO=0;for(int i=0;i<slen;i++)//进行大小写转换if(message[i]>='a'&&message[i]<='z')message[i]=message[i]-'a'+'A';//message[i]=toupper(message[i]);slen=Write(sc,message,slen);//将转换后的信息发回给客户端}Close(sc);//关闭文件描述符Close(ss);return 0;
}

第二版服务器(多进程多并发服务器,直接用fork创建子进程处理客户端请求)

#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "wrap.h"//宏定义
#define MAXLEN 100  //设置监听上限
#define SERVER_PORT 8888  //绑定的端口void catch_child(int signum){while(waitpid(0, NULL,WNOHANG)>0);return ;
}int main(int argc, char *argv[])
{int lfd=0,cfd=0,slen=0;//创建套接字pid_t pid;//创建子进程char message[1024]={0},client_ip[1024]={0};//创建字符串来作为缓冲区,或用BUFSIZ=4096struct sockaddr_in server_addr,client_addr;//创建服务器端和客户端的地址结构socklen_t addrlen;//地址结构的长度bzero(&server_addr,sizeof server_addr);//清零server_addr.sin_family = AF_INET;//协议族server_addr.sin_port = htons(SERVER_PORT);//绑定端口server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//绑定IPint opt=1;setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));//设置端口复用lfd = Socket(AF_INET,SOCK_STREAM,0);Bind(lfd,(struct sockaddr*)&server_addr,sizeof server_addr);//给socket绑定地址结构Listen(lfd,MAXLEN);//设置监听上限addrlen = sizeof(struct sockaddr);printf("Accepting connections ...\n");while(1){cfd = Accept(lfd,(struct sockaddr*)&client_addr,&addrlen);printf("client ip:%s,port:%d 进入\n",inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,client_ip,sizeof(client_ip)),ntohs(client_addr.sin_port));//inet_ntop:将网络字节序转为本地字节序//ntohs:将网络端口转为本地端口pid=fork();if(pid==0){Close(lfd);while(1){slen = Read(cfd,message,1024);//接收信息if(slen==0){Close(cfd);exit(1);}Write(1,message,slen);//将收到的信息输出,STDOUT_FILENO=1,STDIN_FILENO=0;for(int i=0;i<slen;i++)//进行大小写转换if(message[i]>='a'&&message[i]<='z')message[i]=message[i]-'a'+'A';//message[i]=toupper(message[i]);slen=Write(cfd,message,slen);//将转换后的信息发回给客户端}Close(cfd);break;}else if(pid < 0) perr_exit("fork error");else{struct sigaction act;//-----还不知道这是在干嘛act.sa_handler=catch_child;sigemptyset(&act.sa_mask);act.sa_flags = 0;ret = sigaction(SIGCHLD,&act,NULL);if(ret!=0) perr_exit("sigaction error");Close(cfd);continue;	}}Close(lfd);//关闭文件描述符return 0;
}

第三版服务器(多线程多并发服务器,创建子线程处理客户端请求,多线程在编译时要加-pthread,在makefile文件中加上即可)

#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <pthread.h>
#include "wrap.h"#define MAXLISTEN 100  //设置监听上限
#define MAXLINE 80  //缓冲区大小
#define SERVER_PORT 8888  //绑定的端口
#define MAXCLIENT 256 //最大客户端数量struct client_info{struct sockaddr_in client_addr;int connfd;
};
void *do_work(void *arg){int slen;struct client_info *temp = (struct client_info*)arg;char buf[MAXLINE],client_ip[1024];char str[INET_ADDRSTRLEN];pthread_detach(pthread_self());while(1){slen=Read(temp->connfd, buf, MAXLINE);if(slen == 0){printf("client ip:%s quit\n",inet_ntop(AF_INET,&(*temp).client_addr.sin_addr,client_ip,sizeof(client_ip)));break;}Write(1,buf,slen);//输出到本地printf(" received ip:%s at port:%d :",inet_ntop(AF_INET,&(*temp).client_addr.sin_addr,client_ip,sizeof(client_ip)),ntohs((*temp).client_addr.sin_port));//进行处理for(int i=0;i<slen;i++)if(buf[i]>='a'&&buf[i]<='z')buf[i]=buf[i]-'a'+'A';Write(temp->connfd,buf,slen);//将改好的信息发回客户端}Close(temp->connfd);return (void*)0;
}
int main(int argc, char *argv[])
{int lfd=0,cfd=0;//创建套接字int i=0;//i为线程编号struct sockaddr_in server_addr,client_addr;//创建服务器端的地址结构socklen_t addrlen;//地址结构的长度char client_ip[1024];pthread_t tid;struct client_info client[MAXCLIENT];//创建客户端地址结构bzero(&server_addr,sizeof server_addr);//清零server_addr.sin_family = AF_INET;//协议族server_addr.sin_port = htons(SERVER_PORT);//绑定端口server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//绑定IPint opt=1;setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));//设置端口复用lfd = Socket(AF_INET,SOCK_STREAM,0);Bind(lfd,(struct sockaddr*)&server_addr,sizeof server_addr);//给socket绑定地址结构Listen(lfd,MAXLISTEN);//设置监听上限addrlen = sizeof(struct sockaddr);printf("Accepting connections ...\n");while(1){cfd = Accept(lfd,(struct sockaddr*)&client_addr,&addrlen);printf("client ip:%s,port:%d 进入\n",inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,client_ip,sizeof(client_ip)),ntohs(client_addr.sin_port));client[i].client_addr=client_addr;client[i].connfd=cfd;/*达到线程最大数时,pthread_create出错处理,增加服务器稳定性*/pthread_create(&tid, NULL, do_work, (void*)&client[i]);i++;}Close(lfd);return 0;
}

第四版服务器(使用select多路IO转接(借助内核,select用来监听客户端请求))

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "wrap.h"#define MAXLISTEN 100  //设置监听上限
#define MAXLINE 80  //缓冲区大小
#define SERVER_PORT 8888  //设置服务端的端口int main(int argc, char *argv[])
{int lfd,cfd,sockfd,slen,ret,i;//创建套接字int maxi;//用来保存最大的文件描述符int maxfd,client[FD_SETSIZE];//最大文件描述符、客户端文件描述符集合,FD_SETSIZE默认为1024pid_t pid;//创建子进程char buf[MAXLINE],str[INET_ADDRSTRLEN];//创建字符串来作为缓冲区,或用BUFSIZ=4096,str用来使用inet_ntop函数struct sockaddr_in server_addr,client_addr;//创建服务器端和客户端的地址结构socklen_t addrlen;//地址结构的长度fd_set rset,allset;//文件描述符集合,创建监听集合int opt=1;setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));//设置端口复用lfd = Socket(AF_INET,SOCK_STREAM,0);bzero(&server_addr,sizeof server_addr);//清零server_addr.sin_family = AF_INET;//协议族server_addr.sin_port = htons(SERVER_PORT);//绑定端口server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//绑定IPBind(lfd,(struct sockaddr*)&server_addr,sizeof server_addr);//给socket绑定地址结构Listen(lfd,MAXLISTEN);//设置监听上限maxfd = lfd;maxi=-1;for(i=0;i<FD_SETSIZE;i++)client[i]=-1;//对客户端文件描述符集合进行初始化FD_ZERO(&allset); //将监听集合清空FD_SET(lfd,&allset);//将lfd添加到读集合中。addrlen = sizeof(struct sockaddr);printf("Accepting connections ...\n");while(1){rset=allset;//保存监听集合ret = select(maxfd+1,&rset,NULL,NULL,NULL); //监听文件描述符集合对应事件if(ret<0)perr_exit("select error");if(FD_ISSET(lfd,&rset)){//1 在,0 不在cfd = Accept(lfd,(struct sockaddr*)&client_addr,&addrlen);//建立连接,不会阻塞printf("client ip:%s at port:%d access\n",inet_ntop(AF_INET, &client_addr.sin_addr, str, sizeof(str)),ntohs(client_addr.sin_port));for(i=0;i<FD_SETSIZE;i++)if(client[i]<0){client[i]=cfd;break;}if (i == FD_SETSIZE) {/* 达到select能监控的文件个数上限 1024 */fputs("too many clients\n", stderr);exit(1);}FD_SET(cfd,&allset);//将新产生的fd添加到监听通信描述符集合中if(maxfd<cfd)maxfd=cfd;//select第一个参数需要if(i>maxi)maxi=i;//更新client[]数组中的最大文件描述符if(--ret == 0) continue;//只有lfd事件,后续的for不执行}for(i=0;i<=maxi;i++){//处理满足都事件的fdif((sockfd = client[i])<0) continue;//将client[i]赋值给sockfdif(FD_ISSET(sockfd,&rset)){//找到满足读事件的fdslen = Read(sockfd,buf,sizeof buf);if(slen == 0){//当客户端关闭连接时,服务端也关闭连接/*printf("client ip %s at port %d quit\n",inet_ntop(AF_INET, &client_addr.sin_addr, str, sizeof(str)),ntohs(client_addr.sin_port));*/Close(sockfd);FD_CLR(sockfd,&allset);//解除select对此文件描述符的监控client[i]=-1;}else if(slen>0){/*printf("received from %s at port %d :",inet_ntop(AF_INET, &client_addr.sin_addr, str, sizeof(str)),ntohs(client_addr.sin_port));*/Write(1,buf,slen);for(int j=0;j<slen;j++)//进行处理if(buf[j]>='a'&&buf[j]<='z')buf[j]=buf[j]-'a'+'A';slen = Write(sockfd,buf,slen);}if(--ret == 0)break;}	}}Close(lfd);//关闭文件描述符return 0;
}

第五版服务器(poll多路IO转接,poll是半成品,了解即可)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>
#include <errno.h>
#include "wrap.h"#define MAXLISTEN 100  //设置监听上限
#define MAXLINE 80  //缓冲区大小
#define SERVER_PORT 8888  //设置服务端的端口
#define OPEN_MAX 1024int main(int argc, char *argv[])
{int lfd,cfd,sockfd,slen,ret,i,maxi;//创建套接字,maxi为用来保存最大的文件描述符char buf[MAXLINE],str[INET_ADDRSTRLEN];//创建字符串来作为缓冲区,或用BUFSIZ=4096//str用来使用inet_ntop函数,INET_ADDESTRLEN=16struct sockaddr_in server_addr,client_addr;//创建服务器端和客户端的地址结构struct pollfd client[OPEN_MAX];socklen_t addrlen;//地址结构的长度int opt=1;setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));//设置端口复用lfd = Socket(AF_INET,SOCK_STREAM,0);bzero(&server_addr,sizeof server_addr);//清零server_addr.sin_family = AF_INET;//协议族server_addr.sin_port = htons(SERVER_PORT);//绑定端口server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//绑定IPBind(lfd,(struct sockaddr*)&server_addr,sizeof server_addr);//给socket绑定地址结构Listen(lfd,MAXLISTEN);//设置监听上限maxi=0;client[0].fd=lfd;client[0].events=POLLRDNORM;for(i=1;i<OPEN_MAX;i++)client[i].fd=-1;addrlen = sizeof(struct sockaddr);printf("Accepting connections ...\n");while(1){ret=poll(client,maxi+1,-1);if(client[0].revents & POLLRDNORM){//处理lfdcfd=Accept(lfd,(struct sockaddr*)&client_addr,&addrlen);printf("client ip:%s at port:%d access\n",inet_ntop(AF_INET, &client_addr.sin_addr, str, sizeof(str)),ntohs(client_addr.sin_port));for(i=1;i<OPEN_MAX;i++)if(client[i].fd<0){client[i].fd=cfd;//找到client中空闲的位置并将客户端的文件描述符放入break;}if(i==OPEN_MAX) perr_exit("to many client");//客户端数量过多client[i].events=POLLRDNORM;if(i>maxi)maxi=i;if(--ret<=0)continue;}for(i=1;i<=maxi;i++){//处理cfdsockfd=client[i].fd;if(sockfd<0)continue;if(client[i].revents & (POLLRDNORM | POLLERR)){slen=Read(sockfd,buf,sizeof buf);if(slen<0){if(errno == ECONNRESET){//收到RST标志printf("client[%d](ip:%s) aborted connection\n",i,inet_ntop(AF_INET, &client_addr.sin_addr, str, sizeof(str)));Close(sockfd);client[i].fd=-1;}else perr_exit("read error");}else if(slen == 0){//说明客户端先关闭连接printf("client[%d](ip:%s) closed connection\n",i,inet_ntop(AF_INET, &client_addr.sin_addr, str, sizeof(str)));Close(sockfd);client[i].fd=-1;}else {for(int j=0;j<slen;j++)if(buf[j]>='a'&&buf[j]<='z')buf[j]=buf[j]-'a'+'A';slen=Write(sockfd,buf,slen);}if(--ret<=0)break;}}}Close(lfd);//关闭文件描述符return 0;
}

第六版服务器(epoll多路IO转接)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <errno.h>
#include "wrap.h"#define MAXLISTEN 100  //设置listen监听上限
#define MAXLINE 80  //缓冲区大小
#define SERVER_PORT 8888  //设置服务端的端口
#define OPEN_MAX 1024int main(int argc, char *argv[])
{int lfd,cfd,sockfd,slen,ret,res,i,j,maxi,efd;//创建套接字,maxi为用来保存最大的文件描述符int client[OPEN_MAX];char buf[MAXLINE],str[INET_ADDRSTRLEN];//创建字符串来作为缓冲区,或用BUFSIZ=4096//str用来使用inet_ntop函数,INET_ADDESTRLEN=16struct sockaddr_in server_addr,client_addr;//创建服务器端和客户端的地址结构struct epoll_event tep,ep[OPEN_MAX];//tep为临时变量socklen_t addrlen;//地址结构的长度int opt=1;setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));//设置端口复用lfd = Socket(AF_INET,SOCK_STREAM,0);bzero(&server_addr,sizeof server_addr);//清零server_addr.sin_family = AF_INET;//协议族server_addr.sin_port = htons(SERVER_PORT);//绑定端口server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//绑定IPBind(lfd,(struct sockaddr*)&server_addr,sizeof server_addr);//给socket绑定地址结构Listen(lfd,MAXLISTEN);//设置监听上限maxi = -1;for(i = 0;i < OPEN_MAX;i++) client[i] = -1;efd = epoll_create(OPEN_MAX);if(efd < 0) perr_exit("epoll_create error");tep.events = EPOLLIN;//设置临时变量tep.data.fd = lfd;res = epoll_ctl(efd,EPOLL_CTL_ADD,lfd,&tep);if(res < 0) perr_exit("epoll_ctl error");addrlen = sizeof(struct sockaddr);printf("Accepting connections ...\n");while(1){ret = epoll_wait(efd, ep, OPEN_MAX, -1);//阻塞监听,返回监听到的文件描述符数量if(ret < 0) perr_exit("epoll_wait error");for(i = 0;i < ret; i++){if(!(ep[i].events & EPOLLIN)) continue;if(ep[i].data.fd == lfd){cfd = Accept(lfd,(struct sockaddr *)&client_addr,&addrlen);printf("client ip:%s at port %d access\n",inet_ntop(AF_INET,&client_addr.sin_addr,str,sizeof str),ntohs(client_addr.sin_port));for(j=0;j<OPEN_MAX;j++)//找一个空位置存放客户端的文件描述符if(client[j] < 0){client[j]=cfd;break;}if(j == OPEN_MAX) perr_exit("too many clients");if(j > maxi) maxi=j;tep.events = EPOLLIN;tep.data.fd = cfd;res = epoll_ctl(efd,EPOLL_CTL_ADD,cfd,&tep);if(res < 0)perr_exit("epoll_ctl error");}else {sockfd = tep.data.fd;slen = Read(sockfd,buf,sizeof buf);if(slen == 0){for(j=0;j<=maxi;j++)if(client[j]==sockfd){client[j]=-1;break;}res = epoll_ctl(efd,EPOLL_CTL_DEL,sockfd,NULL);if(res < 0) perr_exit("eopll_ctl error");Close(sockfd);printf("client[%d] closed connection\n",j);}else{Write(1,buf,slen);for(j=0;j<slen;j++)if(buf[j]>='a'&&buf[j]<='z')buf[j]=buf[j]-'a'+'A';Write(sockfd,buf,slen);}}}}Close(lfd);//关闭文件描述符Close(efd);return 0;
}

结语

        没啥好说的,找到工作之后就是当牛马了,也不知道能干几年,已经在想养老了(但是养老计算器说还要干40年,我想我真能活到那时候吗)。现在是还没转正,工作也是最近才找到的(因为考研失败摆烂了好长时间),是一家国企965,感觉还行。公司计算机不能接外网,所以我发个博客,用手机看(个人电脑不推荐带),到时候看一些函数作用啥的看自己的代码好想起。

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

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

相关文章

红队信息搜集扫描使用

红队信息搜集扫描使用 红队行动中需要工具化一些常用攻击&#xff0c;所以学习一下 nmap 等的常规使用&#xff0c;提供灵感 nmap 帮助 nmap --help主机扫描 Scan and no port scan&#xff08;扫描但不端口扫描&#xff09;。-sn 在老版本中是 -sP&#xff0c;P的含义是 P…

基于SPI协议的Flash驱动控制

1、理论知识 SPI&#xff08;Serial Peripheral Interface&#xff0c;串行外围设备接口&#xff09;通讯协议&#xff0c;是Motorola公司提出的一种同步串行接口技术&#xff0c;是一种高速、全双工、同步通信总线&#xff0c;在芯片中只占用四根管脚用来控制及数据传输&#…

【Python】利用Python+thinker实现旋转转盘

需求/目的&#xff1a;用Pythonthinker实现转盘&#xff0c;并且能够随机旋转任意角度。 转盘形式&#xff1a; 主界面&#xff1a; from tkinter import *winTk() win.title("大转盘") win.geometry("300x400")win.mainloop() 转盘绘制&#xff1a; 这…

USMART调试组件学习

USMART调试组件学习日记 写于2024/9/24日晚 文章目录 USMART调试组件学习日记1. 简介2. 调试组件组成3.程序流程图4. 移植解析5. 实验效果5. 实验效果 1. 简介 USMART 是由正点原子开发的一个灵巧的串口调试互交组件&#xff0c;通过它你可以通过串口助手调用程序里面的任何函…

SigLIP技术小结

paperhttps://arxiv.org/abs/2303.15343githubhttps://github.com/google-research/big_vision个人博客位置http://myhz0606.com/article/siglip 1 背景 CLIP[1]自提出以来在zero-shot分类、跨模态搜索、多模态对齐等多个领域得到广泛应用。得益于其令人惊叹的能力&#xff0…

备考中考的制胜法宝 —— 全国历年中考真题试卷大全

在中考这场重要的战役中&#xff0c;每一分都至关重要。为了帮助广大考生更好地备考&#xff0c;我们精心整理了这份全国历年中考真题试卷大全&#xff0c;旨在为大家提供最全面、最权威的备考资料。 文章目录 1. 全科覆盖&#xff0c;无遗漏2. 历年真题&#xff0c;权威可靠3.…

数据结构——“AVL树”的四种数据旋转的方法

因为上次普通的二叉搜索树在极端情况下极容易造成我们的链式结构&#xff08;这会导致我们查询的时间复杂度变为O(n)&#xff09;&#xff0c;然而AVL树就很好的解决了这一问题&#xff08;归功于四种旋转的方法&#xff09;&#xff0c;它让我们的树的查询的时间复杂度变得接近…

QT--基础

将默认提供的程序都注释上意义 0101.pro QT core gui #QT表示要引入的类库 core&#xff1a;核心库 gui&#xff1a;图形化界面库 #如果要使用其他库类中的相关函数&#xff0c;则需要加对应的库类后&#xff0c;才能使用 greaterThan(QT_MAJOR_VERSION, 4): QT wid…

关于frp Web界面-----frp Server Dashboard 和 frp Client Admin UI

Web 界面 官方文档&#xff1a;https://gofrp.org/zh-cn/docs/features/common/ui/ 目前 frpc 和 frps 分别内置了相应的 Web 界面方便用户使用。 客户端 Admin UI 服务端 Dashboard 服务端 Dashboard 服务端 Dashboard 使用户可以通过浏览器查看 frp 的状态以及代理统计信…

GD32片内flash读写数据

如有技术问题及技术需求请加作者微信! GD32片内Flash的读写数据是微控制器编程中的常见任务,主要用于存储程序代码、配置参数或用户数据等。以下将详细介绍GD32片内Flash的读写数据方法和程序。 一、GD32 Flash的基本特性 存储空间划分:GD32的Flash存储空间通常分为主存储块…

罕见 P0 故障!上交所崩了 ~

大家好啊&#xff0c;我是董董灿。 昨天&#xff08;9月27号&#xff09;很多朋友可能都刷到一个消息&#xff1a;上交所崩了。 原因是在近期经济政策的刺激下&#xff0c;我大A股市场出现反弹&#xff0c;很多投资者纷纷涌入大A进行交易。 A 股反弹本来是件好事&#xff0c…

常见网络服务搭建之SSH服务搭建

SSH为Secure Shell的缩写&#xff0c;由IETF的网络小组&#xff08;Network Working Group&#xff09;所制定的建立在应用层基础上的安全协议。SSH是较可靠&#xff0c;专为远程登录会话和其他网络服务提供安全性的协议&#xff0c;利用SSH协议可以有效防止远程管理过程中的信…

计算机毕业设计 招生宣传管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

代码随想录算法训练营第十七天|654.最大二叉树 617.合并二叉树 700.二叉搜索树中的搜索 98.验证二叉搜索树

654.最大二叉树 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下&#xff1a; 二叉树的根是数组中的最大元素。左子树是通过数组中最大值左边部分构造出的最大二叉树。右子树是通过数组中最大值右边部分构造出的最大二叉树。 通过给定的数组构建最大二…

番外篇 | 复现AC-YOLOv5,进行自动化织物缺陷检测

前言:Hello大家好,我是小哥谈。我们提出了一种基于AC-YOLOv5的新型纺织缺陷检测方法。将空洞空间金字塔池化(ASPP)模块引入YOLOv5主干网络中,提出了squeeze-and-excitation(CSE)通道注意力模块,并将其引入到YOLOv5主干网络中。🌈 目录 🚀1.基础概念 🚀2.添…

Chrome浏览器如何修改语言(修改成英文、中文)

一、背景 有的时候需要修改chrome浏览器的语言&#xff0c;比如如下是中文&#xff0c;我要修改成英文 二、下面的方法已经无效了 在语言里添加"英语"并且置顶&#xff0c;试了很久&#xff0c;设置完后重启浏览器什么的&#xff0c;都无法改成英文。 这个可能…

ECMAScript 与 JavaScript 的区别详解

ECMAScript 与 JavaScript 的区别详解 在前端开发的学习过程中&#xff0c;很多开发者会遇到两个常见的术语&#xff1a;ECMAScript 和 JavaScript。这两个术语常常被混淆&#xff0c;因为它们密切相关&#xff0c;甚至有时被认为是同一件事。本文将详细解析 ECMAScript 和 Ja…

青动CRM V3.2.1

全面解决企业销售团队的全流程客户服务难题旨在助力企业销售全流程精细化、数字化管理&#xff0c;全面解决企业销售团队的全流程客户服务难题&#xff0c;帮助企业有效盘活客户资源、量化销售行为&#xff0c;合理配置资源、建立科学销售体系&#xff0c;提升销售业绩。标准授…

【面试题】软件测试实习(含答案)

软件测试实习常见面试题&#xff0c;主要是功能测试相关的基础问题 目录 一、软件测试基础 1、介绍一下你最近的项目&#xff0c;以及工作职责 2、软件项目的测试流程? 3、黑盒测试与白盒测试的区别? 4、黑盒测试常见的设计方法?怎么理解等价类方法和边界值方法 1&…

言语理解(2)

B B出现在文章中的第一句话&#xff0c;属于转折前的内容非重点 在这一过程中&#xff0c;属于对前面的指代&#xff0c;后面可以引出文章中的中心内容 A D没有提及到农村&#xff0c;C选项和文段中的最后一句话是相契合的 B 色彩是文章中的主题词&#xff0c;不过属于转折&…