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

linux网络编程实战

前言

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

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

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

使用环境

makefile文件

        直接将所有文件复制到同一个目录下,然后打开终端使用make命令就全部编译好了。

# 定义编译器
CXX=gcc# 定义编译选项,-Wall表示将所有警告打开,这里注释掉
# CFLAGS=-Wall# 定义多个目标文件
TARGET=client
TARGET1=server1
TARGET2=server2
TARGET3=server3
TARGET4=server4
TARGET5=server5
TARGET6=server6# 定义多个源文件
SRC=client.c wrap.c
SRC1=server1.c wrap.c
SRC2=server2.c wrap.c
SRC3=server3.c wrap.c
SRC4=server4.c wrap.c
SRC5=server5.c wrap.c
SRC6=server6.c wrap.c# 默认目标
all: $(TARGET) $(TARGET1) $(TARGET2) $(TARGET3) $(TARGET4) $(TARGET5) $(TARGET6)# 编译第一个文件
$(TARGET): $(SRC)$(CXX) -o $(TARGET) $(SRC)
# 编译其他文件
$(TARGET1): $(SRC1)$(CXX) -o $(TARGET1) $(SRC1)
$(TARGET2): $(SRC2)$(CXX) -o $(TARGET2) $(SRC2)
$(TARGET3): $(SRC3)$(CXX) -o $(TARGET3) $(SRC3) -pthread
$(TARGET4): $(SRC4)$(CXX) -o $(TARGET4) $(SRC4)
$(TARGET5): $(SRC5)$(CXX) -o $(TARGET5) $(SRC5)
$(TARGET6): $(SRC6)$(CXX) -o $(TARGET6) $(SRC6)# 清理编译生成的文件
.PHONY: clean
clean:rm -f  $(TARGET) $(TARGET1) $(TARGET2) $(TARGET3) $(TARGET4) $(TARGET5) $(TARGET6)

错误处理函数封装头文件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;
}

第一版服务器(直接发送接受,只能一次且一个客户端)server1.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创建子进程处理客户端请求)server2.c

#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,ret;//创建套接字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文件中加上即可)server3.c

#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用来监听客户端请求))server4.c

#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是半成品,了解即可)server5.c

#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转接)server6.c

#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,感觉还行。公司计算机不能接外网,所以我发个博客,用手机看(个人电脑不推荐带),到时候看一些函数作用啥的看自己的代码好想起。

相关文章:

linux网络编程实战

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

网络基础 【HTTP】

&#x1f493;博主CSDN主页:麻辣韭菜&#x1f493;   ⏩专栏分类&#xff1a;Linux初窥门径⏪   &#x1f69a;代码仓库:Linux代码练习&#x1f69a; &#x1f4bb;操作环境&#xff1a; CentOS 7.6 华为云远程服务器 &#x1f339;关注我&#x1faf5;带你学习更多Linux知识…...

[Linux#61][UDP] port | netstat | udp缓冲区 | stm32

目录 0. 预备知识 1. 端口号的划分范围 2. 认识知名端口号 3. netstat 命令 4. pidof 命令 二.UDP 0.协议的学习思路 1. UDP 协议报文格式 报头与端口映射&#xff1a; 2. UDP 的特点 面向数据报&#xff1a; 3. UDP 的缓冲区 4. UDP 使用注意事项 5. 基于 UDP 的…...

定义类方法的错误总结

struct Renderer {vector<function<void(vector<string>)>> fileDropListeners;// 定义一个方法&#xff0c;它是将一个函数作为输入&#xff0c;callback是形参void print(function<void(float)> callback_func);void onFileDrop(function<void(ve…...

Redis --- 第三讲 --- 通用命令

一、get和set命令 Redis中最核心的两个命令 get 根据key来取value set 把key和value存储进去 redis是按照键值对的方式存储数据的。必须要先进入到redis客户端。 语法 set key value &#xff1a; key和value都是字符串。 对于上述这里的key value 不需要加上引号&#…...

【Linux】进程间关系与守护进程

超出能力之外的事&#xff0c; 如果永远不去做&#xff0c; 那你就永远无法进步。 --- 乌龟大师 《功夫熊猫》--- 进程间关系与守护进程 1 进程组2 会话3 控制终端4 作业控制5 守护进程 1 进程组 之前我们提到了进程的概念&#xff0c; 其实每一个进程除了有一个进程 ID(P…...

【可视化大屏】将柱状图引入到html页面中

到这里还是用的死数据&#xff0c;先将柱状图引入html页面测试一下 根据上一步echarts的使用步骤&#xff0c;引入echarts.js后需要初始化一个实例对象&#xff0c;所以新建一个index.js文件来进行创建实例化对象和配置数据信息等。 //在index.html引入<script src"j…...

gm/ID设计方法学习笔记(一)

前言&#xff1a;为什么需要gm/id &#xff08;一&#xff09;主流设计方法往往侧重于强反型区&#xff08;过驱>0.2V&#xff09;&#xff0c;低功耗设计则侧重于弱反型区&#xff08;<0&#xff09;&#xff0c;但现在缺乏对中反型区的简单和准确的手算模型。 1.对于…...

高度细化的SAGA模式实现:基于Spring Boot与RabbitMQ的跨服务事务

场景与技术栈 场景&#xff1a;电商系统中的订单创建流程&#xff0c;涉及订单服务&#xff08;Order Service&#xff09;、库存服务&#xff08;Inventory Service&#xff09;、支付服务&#xff08;Payment Service&#xff09;。 技术栈&#xff1a; Java 11 Spring Bo…...

Vue工程化开发

Vue工程化开发 一、工程化开发和脚手架 1.开发Vue的两种方式 核心包传统开发模式&#xff1a;基于html / css / js 文件&#xff0c;直接引入核心包&#xff0c;开发 Vue。工程化开发模式&#xff1a;基于构建工具&#xff08;例如&#xff1a;webpack&#xff09;的环境中开…...

Ray_Tracing_The_Next_Week下

5image Texture Mapping 图像纹理映射 我们之前虽然在交点信息新增了uv属性&#xff0c;但其实并没有使用&#xff0c;而是通过p交点笛卡尔坐标确定瓷砖纹理或者大理石噪声纹理的值 现在通过uv坐标读取图片&#xff0c;通过std_image库stbi_load&#xff08;path&#xff09;…...

ES索引生命周期管理

基于如何 定时删除ES索引过期数据 而引发的一系列关于ES索引生命周期管理ILM(Index Lifecycle Management)的学习 快速上手 &#xff1a;定时删除ES索引中的过期数据 1. ILM解决什么问题&#xff1f; ES从6.7版本引入ILM&#xff0c;通过ILM可以解决哪些问题呢? 自动新建…...

Oracle数据库体系结构基础

关于Oracle体系结构 基于Oracle11g体系结构 目标&#xff1a; 了解Oracle体系结构掌握逻辑存储结构掌握物理存储结构熟悉Oracle服务器结构熟悉常用的数据字典 Oracle数据库管理中的重要的三个概念 实例&#xff08;instance):实例是指一组Oracle后台进程以及在服务器中分配…...

QT学习笔记4.5(文件、参数文件)

QT学习笔记4.5&#xff08;文件、参数文件&#xff09; 1.保存配置参数 1.使用QSettings保存到注册表&#xff0c;ini文件 2.文件存储&#xff1a;使用 QFile 和其他类将参数保存到文本文件、二进制文件、XMLWENJIAN、JSON 文件等。 文本文件&#xff1a;以简单的键值对格式…...

服务器虚拟化的详细学习要点

服务器虚拟化的详细学习要点可以归纳为以下几个方面: 1. 基本概念与原理 定义与原理:了解服务器虚拟化是一种将物理服务器资源转化为虚拟服务器资源的技术,允许在一台物理服务器上运行多个虚拟服务器。 虚拟化层次:理解虚拟化的不同层次,如裸机虚拟化(Type 1)和托管虚…...

创建一个Java Web API项目

创建一个Java Web API涉及多个步骤和技术栈&#xff0c;包括项目设置、依赖管理、数据访问层实现、业务逻辑实现、控制层开发以及测试和部署。在这篇详解中&#xff0c;我将带领你通过一个完整的Java Web API实现流程&#xff0c;采用Spring Boot和MyBatis-Plus作为主要技术工具…...

对称加密算法的使用Java和C#

1. JAVA中的使用 1.1.原生使用 Main函数代码 import symmetric_encryption.AESExample; import symmetric_encryption.BlowfishExample; import symmetric_encryption.DESExample; import symmetric_encryption.TripleDESExample; public class App { public static…...

10款好用的开源 HarmonyOS 工具库

大家好&#xff0c;我是 V 哥&#xff0c;今天给大家分享10款好用的 HarmonyOS的工具库&#xff0c;在开发鸿蒙应用时可以用下&#xff0c;好用的工具可以简化代码&#xff0c;让你写出优雅的应用来。废话不多说&#xff0c;马上开整。 1. efTool efTool是一个功能丰富且易用…...

ubuntu22.04中备份Iptables的设置

在 Ubuntu 22.04 中备份 iptables 的设置&#xff0c;您可以采用以下几种方法&#xff1a; 使用 iptables-save 命令&#xff1a; 您可以使用 iptables-save 命令将当前的 iptables 规则保存到文件中。例如&#xff0c;要将规则保存到 /etc/iptables/rules.v4 文件中&#xff0…...

(PyTorch) 深度学习框架-介绍篇

前言 在当今科技飞速发展的时代&#xff0c;人工智能尤其是深度学习领域正以惊人的速度改变着我们的世界。从图像识别、语音处理到自然语言处理&#xff0c;深度学习技术在各个领域都取得了显著的成就&#xff0c;为解决复杂的现实问题提供了强大的工具和方法。 PyTorch 是一个…...

若依从redis中获取用户列表

因为若依放入用户的时候&#xff0c;会在减值中添加随机串&#xff0c;所以用户的key会在redis中变成&#xff1a; login_tokens:6af07052-b76d-44dd-a296-1335af03b2a6 这样的样子。 如果用 Set<Object> items redisService.redisTemplate.keys("login_tokens&…...

文件上传之%00截断(00截断)以及pikachu靶场

pikachu的文件上传和upload-lab的文件上传 目录 mime type类型 getimagesize 第12关%00截断&#xff0c; 第13关0x00截断 差不多了&#xff0c;今天先学文件上传白名单&#xff0c;在网上看了资料&#xff0c;差不多看懂了&#xff0c;但是还有几个地方需要实验一下&#…...

Chainlit集成LlamaIndex并使用通义千问实现和数据库交互的网页对话应用(text2sql)

前言 我在之前的几篇文章中写了如何使用Chainlit集成Langchain并使用通义千问实现和数据库交互的网页对话应用&#xff0c;但是发现Langchain的几种和数据库交互的组件都不够让我满意&#xff0c;虽然已经满足了大部分场景的需求&#xff0c;但是问题还是很多&#xff0c;比如…...

计组复习笔记

计组笔记 汇编部分 通用寄存器&#xff08;General Registers&#xff09;: AX (Accumulator): 用于累加运算&#xff0c;也是乘法和除法的默认寄存器。BX (Base Register): 可以用作一个基址寄存器&#xff0c;通常用于存放数据的基地址。CX (Counter Register): 通常用于循环…...

62. 环境贴图2

环境贴图作用测试 实际生活中光源照射到一个物体上&#xff0c;这个物体反射出去的光线也会影响其他的物体&#xff0c;环境贴图就是用一种简单方式&#xff0c;近似模拟一个物体周边环境对物体表面的影响。 测试&#xff1a;对于PBR材质&#xff0c;如果threejs三维场景不添…...

MATLAB中数据导入与导出的全面指南

在MATLAB中&#xff0c;数据的导入与导出是数据处理工作流中的两个基本步骤。导入是将外部数据加载到MATLAB工作区的过程&#xff0c;而导出则是将工作区中的数据保存到外部文件中。这两个步骤对于数据分析、可视化和结果共享至关重要。本文将详细介绍如何在MATLAB中进行数据的…...

Jenkins从入门到精通,构建高效自动化流程

目录 一、Jenkins简介1、Jenkins的历史与发展&#xff08;1&#xff09;Jenkins的起源&#xff08;2&#xff09;Jenkins的发展&#xff08;3&#xff09;Jenkins的社区与生态系统&#xff08;4&#xff09;Jenkins在我国的发展 2、Jenkins的核心功能3、Jenkins的应用场景 二、…...

【Android 13源码分析】Activity生命周期之onCreate,onStart,onResume-2

忽然有一天&#xff0c;我想要做一件事&#xff1a;去代码中去验证那些曾经被“灌输”的理论。                                                                                  – 服装…...

如何在电脑上浏览手机界面

联想浏览器中&#xff0c;点击右键-》检查&#xff0c;进入开发者工具&#xff1a; 点击如上&#xff0c;红色框框选中的手机浏览模式即可。...

国产RISC-V案例分享,基于全志T113-i异构多核平台!

RISC-V核心优势 全志T113-i是一款双核Cortex-A7@1.2GHz国产工业级处理器平台,并内置玄铁C906 RISC-V和HiFi4 DSP双副核心,可流畅运行Linux系统与Qt界面,并已适配OpenWRT系统、Docker容器技术。 而其中的RISC-V属于超高能效副核心,主频高达1008MHz,标配内存管理单元,可运…...