├── network ├── client_Multiprocess.c ├── client_echo.c ├── client_time.c ├── client_timeMultipro.c ├── epoll.c ├── poll.c ├── select.c ├── serverMultipro_echo.c ├── serverMultithr_echo.c ├── server_Multiprocess_time.c ├── server_Multithread_time.c └── server_echo.c └── operation ├── Linux_304_1_2016220204010_刘高阳.docx ├── cptest.c ├── ls_my.c └── process.c /network/client_Multiprocess.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define DEFAULT_PORT (unsigned short) 7341 14 | #define COMMAND 512 15 | 16 | //并发多进程客户端 需要实现可指定进程数的客户端 17 | static void sig_child(int signo); 18 | void error(char* message); 19 | void trans(int connfd); 20 | /** 21 | * 多进程客户端,接受服务器向其发送的时间,并打印在屏幕之上 22 | * @author superliuliuliu1 23 | * @version 1.0 24 | */ 25 | 26 | int main(int argc, char** argv) 27 | { 28 | int sockfd; 29 | struct sockaddr_in server; 30 | unsigned short port = DEFAULT_PORT; 31 | char* server_ip; 32 | char command[COMMAND]; 33 | pid_t pid; 34 | 35 | 36 | printf("欢迎您使用TIME客户端!\n"); 37 | printf("--------------------------------------------\n"); 38 | if (argc < 2 || argc > 3) 39 | { 40 | printf("使用指南:\n"); 41 | printf("Usage: %s [server ip] [port]\n", argv[0]); 42 | printf("服务器端的默认开放端口号为7341,如果你已经设置请忽略!\n"); 43 | error("Error on input"); 44 | } 45 | 46 | if (argc == 3) 47 | { 48 | port = (unsigned short)atoi(argv[2]); 49 | } 50 | 51 | server_ip = argv[1]; 52 | 53 | sockfd = socket(PF_INET, SOCK_STREAM, 0); 54 | if (sockfd < 0) { 55 | error("Error on socket"); 56 | } 57 | 58 | 59 | memset(&server, 0, sizeof(server)); 60 | server.sin_family = AF_INET; 61 | server.sin_port = htons(port); 62 | server.sin_addr.s_addr = inet_addr(server_ip); 63 | 64 | 65 | //客户端与服务器端相连接 66 | if ((connect(sockfd, (struct sockaddr*)&server, sizeof(server))) < 0) 67 | { 68 | error("Error on connect"); 69 | } 70 | 71 | printf("Begin to get the time(input the time to get the server time or input quit to exit the client)\n"); 72 | 73 | while (true) 74 | { 75 | printf(">>"); 76 | memset(command, 0, COMMAND); 77 | fgets(command, sizeof(command), stdin); 78 | if (command == NULL) 79 | { 80 | continue; 81 | } 82 | else if (strcmp(command, "quit\n") == 0) 83 | { 84 | break; 85 | } 86 | else if (strcmp(command, "time\n") == 0 ) 87 | { 88 | // 89 | signal(SIGCHLD, sig_child); 90 | pid = fork(); 91 | 92 | switch(pid) 93 | { 94 | case -1: 95 | { 96 | perror("Error on fork"); 97 | break; 98 | } 99 | case 0: 100 | { 101 | trans(sockfd); 102 | } 103 | default: 104 | { 105 | break; 106 | } 107 | } 108 | } 109 | else 110 | { 111 | printf("I do not understand what you input, please try again!\n"); 112 | } 113 | 114 | } 115 | close(sockfd); 116 | printf("欢迎您下次继续使用!\n"); 117 | return 0; 118 | 119 | } 120 | 121 | /** 122 | * 错误处理函数:遇到错误退出程序,并输出相关的错误信息 123 | * @author superliuliuliu1 124 | * @version 1.0 125 | * @param message 错误提示信息 126 | */ 127 | void error(char *message) 128 | { 129 | perror(message); 130 | exit(1); 131 | } 132 | 133 | /** 134 | * 客户端发送接受数据 135 | * @author superliuliuliu1 136 | * @version 1.0 137 | * @param connfd [description] 138 | */ 139 | void trans(int connfd) 140 | { 141 | char message[COMMAND]; 142 | memset(message, 0 ,COMMAND); 143 | send(connfd, "time", 4, 0); 144 | recv(connfd, message, sizeof(message), 0); 145 | printf("%s\n", message); 146 | exit(0);//退出子进程 147 | } 148 | 149 | // WNOHANG 如果pid指定的子进程没有结束,则waitpid()函数立即返回0,而不是阻塞在这个函数上等待;如果结束了,则返回该子进程的进程号 150 | static void sig_child(int signo) 151 | { 152 | pid_t pid; 153 | int stat; 154 | //处理僵尸进程 155 | while ((pid = waitpid(-1, &stat, WNOHANG)) >0) 156 | printf("child %d terminated.\n>>", pid); 157 | } 158 | -------------------------------------------------------------------------------- /network/client_echo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define DEFAULT_PORT (unsigned short) 8978 11 | #define MAXSIZE 1024 12 | 13 | 14 | 15 | void error(char* message); 16 | void echo(int sockfd,char* arg); 17 | 18 | /** 19 | * linux 环境下实现echo客户程序 实现代码有两种一种迭代式的实现另一种并发式的实现 20 | * @author superliuliuliu1 21 | * @version 1.0 22 | * @date 2018/10/17 23 | */ 24 | int main(int argc, char **argv) 25 | { 26 | int sockfd; 27 | struct sockaddr_in server; 28 | unsigned short port = DEFAULT_PORT; 29 | char* server_ip; 30 | char recv_buffer[MAXSIZE]; 31 | char message[MAXSIZE]; 32 | 33 | 34 | printf("欢迎您使用ECHO客户端!\n"); 35 | printf("--------------------------------------------\n"); 36 | if (argc < 2 || argc > 3) 37 | { 38 | printf("使用指南:\n"); 39 | printf("Usage: %s [server ip] [port]\n", argv[0]); 40 | printf("服务器端的默认开放端口号为7341,如果你已经设置请忽略!\n"); 41 | error("Error on input"); 42 | } 43 | //设置端口号 44 | if(argc == 3) 45 | { 46 | port = (unsigned short)atoi(argv[2]); 47 | } 48 | 49 | server_ip = argv[1]; 50 | 51 | //创建socket 52 | sockfd = socket(PF_INET, SOCK_STREAM, 0); 53 | if (sockfd < 0) 54 | { 55 | error("Error open the socket!"); 56 | } 57 | 58 | memset(&server, 0, sizeof(server)); 59 | server.sin_family = AF_INET; 60 | server.sin_port = htons(port); 61 | server.sin_addr.s_addr = inet_addr(server_ip); 62 | 63 | //connect 64 | if ((connect(sockfd, (struct sockaddr*)&server, sizeof(server))) < 0) 65 | { 66 | error("Error on connect"); 67 | } 68 | printf("please input words to echo server(input quit to exit the client)\n"); 69 | while (true) 70 | { 71 | printf(">>"); 72 | memset(recv_buffer, 0, MAXSIZE); 73 | if ((fgets(recv_buffer, sizeof(recv_buffer), stdin)) == NULL) 74 | { 75 | error("Error on input"); 76 | } 77 | if (recv_buffer == NULL) 78 | { 79 | continue; 80 | } 81 | else if (strcmp(recv_buffer, "quit\n") == 0) 82 | { 83 | break; 84 | } 85 | else 86 | { 87 | printf(">>"); 88 | echo(sockfd, recv_buffer); 89 | } 90 | } 91 | close(sockfd); 92 | printf("欢迎您下次继续使用!\n"); 93 | return 0; 94 | 95 | } 96 | 97 | void echo(int sockfd,char* arg) 98 | { 99 | char message[MAXSIZE]; 100 | memset(message, 0 ,MAXSIZE); 101 | send(sockfd, arg, strlen(arg), 0); 102 | recv(sockfd, message, sizeof(message), 0); 103 | //printf("message send success! send %d bytes!", (int)strlen(arg)); 104 | 105 | printf("%s", message); 106 | return; 107 | 108 | } 109 | 110 | void error(char* message) 111 | { 112 | perror(message); 113 | exit(1); 114 | } 115 | -------------------------------------------------------------------------------- /network/client_time.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define DEFAULT_PORT (unsigned short) 7341 12 | #define COMMAND 512 13 | 14 | void error(char *message); 15 | void trans(int connfd); 16 | 17 | /** 18 | * 单进程客户端,接受服务器向其发送的时间,并打印在屏幕之上 19 | * @author superliuliuliu1 20 | * @version 1.0 21 | */ 22 | int main(int argc, char** argv) 23 | { 24 | int sockfd; 25 | struct sockaddr_in server; 26 | unsigned short port = DEFAULT_PORT; 27 | char* server_ip; 28 | char command[COMMAND]; 29 | 30 | 31 | printf("欢迎您使用TIME客户端!\n"); 32 | printf("--------------------------------------------\n"); 33 | if (argc < 2 || argc > 3) 34 | { 35 | printf("使用指南:\n"); 36 | printf("Usage: %s [server ip] [port]\n", argv[0]); 37 | printf("服务器端的默认开放端口号为7341,如果你已经设置请忽略!\n"); 38 | error("Error on input"); 39 | } 40 | 41 | if (argc == 3) 42 | { 43 | port = (unsigned short)atoi(argv[2]); 44 | } 45 | 46 | server_ip = argv[1]; 47 | 48 | sockfd = socket(PF_INET, SOCK_STREAM, 0); 49 | if (sockfd < 0) { 50 | error("Error on socket"); 51 | } 52 | 53 | 54 | memset(&server, 0, sizeof(server)); 55 | server.sin_family = AF_INET; 56 | server.sin_port = htons(port); 57 | server.sin_addr.s_addr = inet_addr(server_ip); 58 | 59 | 60 | //客户端与服务器端相连接 61 | if ((connect(sockfd, (struct sockaddr*)&server, sizeof(server))) < 0) 62 | { 63 | error("Error on connect"); 64 | } 65 | 66 | printf("Begin to get the time(input the time to get the server time or input quit to exit the client)\n"); 67 | 68 | while (true) 69 | { 70 | printf(">>"); 71 | memset(command, 0, COMMAND); 72 | fgets(command, sizeof(command), stdin); 73 | if (command == NULL) 74 | { 75 | continue; 76 | } 77 | else if (strcmp(command, "quit\n") == 0) 78 | { 79 | break; 80 | } 81 | else if (strcmp(command, "time\n") == 0 ) 82 | { 83 | // 84 | trans(sockfd); 85 | } 86 | else 87 | { 88 | printf("I do not understand what you input, please try again!\n"); 89 | } 90 | 91 | } 92 | close(sockfd); 93 | printf("欢迎您下次继续使用!\n"); 94 | return 0; 95 | 96 | } 97 | 98 | /** 99 | * 错误处理函数:遇到错误退出程序,并输出相关的错误信息 100 | * @author superliuliuliu1 101 | * @version 1.0 102 | * @param message 错误提示信息 103 | */ 104 | void error(char *message) 105 | { 106 | perror(message); 107 | exit(1); 108 | } 109 | 110 | /** 111 | * 客户端发送接受数据 112 | * @author superliuliuliu1 113 | * @version 1.0 114 | * @param connfd [description] 115 | */ 116 | void trans(int connfd) 117 | { 118 | char message[COMMAND]; 119 | memset(message, 0 ,COMMAND); 120 | send(connfd, "time", 4, 0); 121 | recv(connfd, message, sizeof(message), 0); 122 | printf("%s\n", message); 123 | } 124 | -------------------------------------------------------------------------------- /network/client_timeMultipro.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define DEFAULT_PORT (unsigned short) 7341 14 | #define COMMAND 512 15 | 16 | //并发多进程客户端 需要实现可指定进程数的客户端 17 | static void sig_child(int signo); 18 | void error(char* message); 19 | void trans(int connfd); 20 | 21 | /** 22 | * 多进程客户端, 能够指定生成的进程数,并发的向服务器端发送time命令,而不再采取从命令行获取time命令的形式 23 | * @author superliuliuliu1 24 | * @version 2.0 25 | */ 26 | int main(int argc, char** argv) 27 | { 28 | int sockfd; 29 | struct sockaddr_in server; 30 | unsigned short port = DEFAULT_PORT; 31 | char* server_ip; 32 | pid_t pid; 33 | int multi_number; 34 | 35 | printf("欢迎您使用TIME多进程客户端模拟测试并发程序!\n"); 36 | printf("--------------------------------------------\n"); 37 | if (argc != 4) 38 | { 39 | printf("使用指南:\n"); 40 | printf("Usage: %s [server ip] [port] [the number of process you want to test]\n", argv[0]); 41 | printf("服务器端的默认开放端口号为7341,如果你已经设置请忽略!\n"); 42 | error("Error on input"); 43 | } 44 | 45 | port = (unsigned short)atoi(argv[2]); 46 | multi_number = atoi(argv[3]); 47 | server_ip = argv[1]; 48 | 49 | sockfd = socket(PF_INET, SOCK_STREAM, 0); 50 | if (sockfd < 0) { 51 | error("Error on socket"); 52 | } 53 | 54 | memset(&server, 0, sizeof(server)); 55 | server.sin_family = AF_INET; 56 | server.sin_port = htons(port); 57 | server.sin_addr.s_addr = inet_addr(server_ip); 58 | 59 | //客户端与服务器端相连接 60 | if ((connect(sockfd, (struct sockaddr*)&server, sizeof(server))) < 0) 61 | { 62 | error("Error on connect"); 63 | } 64 | 65 | printf("本程序为模拟多个客户端向并发服务器发送命令过程因此您不需要输入任何内容!\n"); 66 | int i; 67 | signal(SIGCHLD, sig_child); 68 | for (i = 0; i < multi_number; i++) 69 | { 70 | pid = fork(); 71 | switch (pid) 72 | { 73 | case -1: 74 | { 75 | close(sockfd); 76 | error("Error on fork"); 77 | } 78 | case 0: 79 | { 80 | trans(sockfd); 81 | break; 82 | } 83 | default: 84 | { 85 | waitpid(pid, NULL, 0); 86 | break; 87 | } 88 | } 89 | } 90 | close(sockfd); 91 | return 0; 92 | } 93 | 94 | /** 95 | * 错误处理函数:遇到错误退出程序,并输出相关的错误信息 96 | * @author superliuliuliu1 97 | * @version 1.0 98 | * @param message 错误提示信息 99 | */ 100 | void error(char *message) 101 | { 102 | perror(message); 103 | exit(1); 104 | } 105 | 106 | /** 107 | * 客户端发送接受数据 108 | * @author superliuliuliu1 109 | * @version 1.0 110 | * @param connfd socket文件描述符 111 | */ 112 | void trans(int connfd) 113 | { 114 | char message[COMMAND]; 115 | memset(message, 0 ,COMMAND); 116 | send(connfd, "time", 4, 0); 117 | recv(connfd, message, sizeof(message), 0); 118 | printf("%s\n", message); 119 | exit(0);//退出子进程 120 | } 121 | 122 | 123 | /** 124 | * 用来捕获子进程退出的消息SIGCHLD的信号处理函数 125 | * @author superliuliuliu1 126 | * @version 1.0 127 | * @lastupdate 2018/11/04 128 | * @param signo 129 | * 130 | */ 131 | static void sig_child(int signo) 132 | { 133 | pid_t pid; 134 | int stat; 135 | //处理僵尸进程 136 | while ((pid = waitpid(-1, &stat, WNOHANG)) >0) 137 | { 138 | printf("child %d terminated.\n", pid); 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /network/epoll.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | #define DEFAULT_PORT (unsigned short) 7341 15 | #define LISTENQUE 10 16 | #define MAXSIZE 1024 17 | #define MAX_FD 1024 18 | #define MAX_EVENTS 20 19 | 20 | void error(char *message); 21 | int timenow(int connfd); 22 | static int setsocket(int port); 23 | void add_event(int epfd, int fd, int mask); 24 | void delete_event(int epfd, int fd, int mask); 25 | 26 | 27 | //编写基于epoll的I/O多路复用并发time服务器 28 | int main(int argc, char** argv) 29 | { 30 | int sockfd, connfd; 31 | struct sockaddr_in client; 32 | socklen_t len = sizeof(struct sockaddr_in); 33 | unsigned short port = DEFAULT_PORT; 34 | int epfd;//use to record epoll_create() 该文件描述符不是用于I/O操作的存在,而是用来记录内核的数据结构的句柄 35 | struct epoll_event evlist[MAX_EVENTS]; //定义一个结构体用来记录待检查文件描述符的相关信息 36 | if (argc > 2) 37 | { 38 | printf("Usage: %s [port]\n", argv[0]); 39 | printf("服务器端的默认开放端口号为7341,如果你已经设置请忽略!\n"); 40 | error("Error on input"); 41 | } 42 | if (argc > 1) { 43 | port = (unsigned short)atoi(argv[1]); 44 | } 45 | //创建监听socket并与server绑定 46 | sockfd = setsocket(port); 47 | 48 | epfd = epoll_create(MAX_FD);//MAX_FD用来指定我们想要通过epoll实例来检查文件描述符的个数 49 | if (epfd == -1) 50 | { 51 | error("Error on epoll_create()"); 52 | } 53 | 54 | add_event(epfd, sockfd, EPOLLIN); 55 | int ready; 56 | int i;//循环变量 57 | 58 | while (true) 59 | { 60 | //事件等待 epoll_wait()相当于select与poll函数 将timeout设置为-1代表调用一直阻塞,直至文件描述符上有事情发生或者是捕捉到了一个信号 61 | ready = epoll_wait(epfd, evlist, MAX_EVENTS, -1); 62 | if (ready == -1) 63 | { 64 | //EINTR错误代表该调用被信号处理历程给中断了,epoll不会自动恢复,因此需要我们加以操作 65 | if (errno == EINTR) 66 | { 67 | continue; 68 | } 69 | error("Error on select()"); 70 | } 71 | else if (ready == 0) 72 | { 73 | continue; 74 | } 75 | else 76 | { //检测监听描述符是否就绪,若就绪则进行下面的建立数据连接准备传输数据,否则continue 77 | for (i = 0; i < ready; i++) 78 | { 79 | int fd1 = evlist[i].data.fd; 80 | if ((fd1 == sockfd) && (evlist[i].events & EPOLLIN)) 81 | { 82 | memset(&client, 0, sizeof(client)); 83 | connfd = accept(sockfd, (struct sockaddr*)&client, &len); 84 | if (connfd < 0) 85 | { 86 | perror("error on accept()"); 87 | break; 88 | } 89 | else if (connfd > MAX_FD) 90 | { 91 | perror("too many clients"); 92 | close(connfd); 93 | } 94 | else 95 | { 96 | printf("此时通信的客户端IP地址:%s\n", inet_ntoa(client.sin_addr)); 97 | //将connfd加入其中 98 | add_event(epfd, connfd, EPOLLIN); 99 | } 100 | } 101 | } 102 | } 103 | for (i = 0; i < ready; i++) 104 | { 105 | if ((evlist[i].data.fd != sockfd) && (evlist[i].events & EPOLLIN)) 106 | { 107 | if (timenow(evlist[i].data.fd) <= 0) 108 | { 109 | close(evlist[i].data.fd); 110 | delete_event(epfd, evlist[i].data.fd, EPOLLIN); 111 | } 112 | } 113 | } 114 | 115 | } 116 | close(epfd); 117 | return 0; 118 | } 119 | 120 | 121 | 122 | /** 123 | * 为了使main程序结构看的更加清晰,选择将创建socket、初始化server、bind的部分提取出来成为setsocket函数 124 | * @author superliuliuliu1 125 | * @version 1.0 126 | * @lastupdate 2018/10/09 127 | * @return sockfd 128 | */ 129 | static int setsocket(int port) { 130 | int sockfd; 131 | struct sockaddr_in server; 132 | int reuse = 1;//used in setsockopt() 133 | 134 | //对server进行初始化 135 | memset(&server, 0, sizeof(server)); 136 | server.sin_port = htons(port); 137 | server.sin_family = AF_INET; 138 | server.sin_addr.s_addr = htonl(INADDR_ANY); 139 | //创建监听socket 140 | sockfd = socket(PF_INET, SOCK_STREAM, 0); 141 | if (sockfd < 0) { 142 | error("Error on socket()"); 143 | } 144 | 145 | //设置套接字选项SO_REUSEADDR 目的在于让本地的端口号能够重用 146 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) 147 | { 148 | close(sockfd); 149 | error("Error on setsockopt()"); 150 | } 151 | 152 | //绑定sock 153 | if ((bind(sockfd, (struct sockaddr*)&server, sizeof(server))) != 0) 154 | { 155 | close(sockfd); 156 | error("Error on bind()"); 157 | } 158 | 159 | //listen设定待连接的最大数目 160 | if (listen(sockfd, LISTENQUE) < 0) 161 | { 162 | close(sockfd); 163 | error("Error on listen()"); 164 | } 165 | return sockfd; 166 | } 167 | 168 | /** 169 | * 错误处理函数:遇到错误退出程序,并输出相关的错误信息 170 | * @author superliuliuliu1 171 | * @version 1.0 172 | * @param message 错误提示信息 173 | */ 174 | void error(char *message) 175 | { 176 | perror(message); 177 | exit(1); 178 | } 179 | 180 | /** 181 | * 接受客户端发来的数据,并将当前的系统时间发送给客户端 182 | * @author superliuliuliu1 183 | * @version 1.0 184 | * @param connfd [description] 185 | */ 186 | int timenow(int connfd) 187 | { 188 | char buffer[MAXSIZE]; 189 | int recv_size; 190 | memset(buffer, 0, MAXSIZE); 191 | time_t ntime; 192 | char timestr[30]; 193 | 194 | if ((recv_size = recv(connfd, buffer, MAXSIZE, 0)) > 0) 195 | { 196 | //接受客户端输入的命令并辨别 若收到time命令则将时间封装到buffer中,并发送出去 197 | if (strcmp(buffer, "time") == 0) 198 | { 199 | printf("Receive time request\n"); 200 | ntime = time(NULL); 201 | struct tm* tm_struct = localtime(&ntime); 202 | memset(timestr, 0, 30); 203 | strftime(timestr, 30, "%Y/%m/%d %H:%M", tm_struct); 204 | printf("%s\n", timestr); 205 | send(connfd , timestr, sizeof(timestr), 0); 206 | memset(buffer, 0, MAXSIZE); 207 | } 208 | } 209 | return recv_size; 210 | } 211 | 212 | /** 213 | * 向其感兴趣的列表中增加一个文件描述符 214 | * @author superliuliuliu1 215 | * @version 1.0 216 | * @lastupdate 18/11/09 217 | * @param epfd [description] 218 | * @param fd [description] 219 | * @param mask events字段上的掩码值 220 | */ 221 | void add_event(int epfd, int fd, int mask) 222 | { 223 | struct epoll_event ev; 224 | ev.events = mask; 225 | ev.data.fd = fd; 226 | epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev); 227 | } 228 | 229 | /** 230 | * 想起感兴趣的列表中删除一个文件描述符 231 | * @author superliuliuliu1 232 | * @version 1.0 233 | * @lastupdate 18/11/09 234 | * @param epfd [description] 235 | * @param fd [description] 236 | * @param mask events字段上的掩码值 237 | */ 238 | void delete_event(int epfd, int fd, int mask) 239 | { 240 | struct epoll_event ev; 241 | ev.events = mask; 242 | ev.data.fd = fd; 243 | epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &ev); 244 | } 245 | -------------------------------------------------------------------------------- /network/poll.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | #define DEFAULT_PORT (unsigned short) 7341 15 | #define LISTENQUE 10 16 | #define MAXSIZE 1024 17 | #define MAX_FD 1024 18 | 19 | void error(char *message); 20 | int timenow(int connfd); 21 | static int setsocket(int port); 22 | 23 | //编写基于poll的I/O多路复用并发time服务器 24 | int main(int argc, char** argv) 25 | { 26 | int sockfd, connfd; 27 | struct sockaddr_in client; 28 | socklen_t len = sizeof(struct sockaddr_in); 29 | unsigned short port = DEFAULT_PORT; 30 | struct pollfd fdset[MAX_FD]; 31 | int maxfd = 0; 32 | int i;//循环变量 33 | int ready;//the number poll return 34 | if (argc > 2) 35 | { 36 | printf("Usage: %s [port]\n", argv[0]); 37 | printf("服务器端的默认开放端口号为7341,如果你已经设置请忽略!\n"); 38 | error("Error on input"); 39 | } 40 | if (argc > 1) { 41 | port = (unsigned short)atoi(argv[1]); 42 | } 43 | //创建监听socket并与server绑定 44 | sockfd = setsocket(port); 45 | 46 | //初始化存储文件描述符信息的集合 47 | fdset[0].fd = sockfd; 48 | fdset[0].events = POLLIN; 49 | for (i= 1; i< MAX_FD; i++) 50 | { 51 | fdset[i].fd = -1; 52 | } 53 | 54 | while (true) 55 | { 56 | //将timeout设置为-1让poll阻塞到描述符集合中有可用的描述符之时 57 | ready = poll(fdset, maxfd + 1, -1); 58 | if (ready == -1) 59 | { 60 | //EINTR错误代表该调用被信号处理历程给中断了,poll不会自动恢复,因此需要我们加以操作 61 | if (errno == EINTR) 62 | { 63 | continue; 64 | } 65 | error("Error on select()"); 66 | } 67 | else if (ready == 0) 68 | { 69 | continue; 70 | } 71 | else 72 | { //检测监听描述符是否就绪,若就绪则进行下面的建立数据连接准备传输数据,否则continue 73 | if (fdset[0].revents & POLLIN) 74 | { 75 | memset(&client, 0, sizeof(client)); 76 | connfd = accept(sockfd, (struct sockaddr*)&client, &len); 77 | if (connfd < 0) 78 | { 79 | perror("error on accept()"); 80 | break; 81 | } 82 | else if (connfd > MAX_FD) 83 | { 84 | perror("too many clients"); 85 | close(connfd); 86 | } 87 | else 88 | { 89 | printf("此时通信的客户端IP地址:%s\n", inet_ntoa(client.sin_addr)); 90 | //将新的文件描述符添加到fdset之中 并更新maxfd 91 | if (connfd > maxfd) 92 | { 93 | maxfd = connfd; 94 | } 95 | for (i = 1; i < MAX_FD; i++) 96 | { 97 | if (fdset[i].fd < 0) 98 | { 99 | fdset[i].fd = connfd; 100 | fdset[i].events = POLLIN; 101 | break;//找到一个空闲的赋值之后便跳出循环 102 | } 103 | } 104 | } 105 | 106 | } 107 | } 108 | for (i = 1; i < MAX_FD; i++) 109 | { 110 | if ((fdset[i].fd > 0) && (fdset[i].revents & POLLIN)) 111 | { 112 | if (timenow(fdset[i].fd) <= 0) 113 | { 114 | fdset[i].fd = -1; 115 | close(fdset[i].fd); 116 | } 117 | } 118 | } 119 | } 120 | close(sockfd); 121 | return 0; 122 | } 123 | 124 | /** 125 | * 为了使main程序结构看的更加清晰,选择将创建socket、初始化server、bind的部分提取出来 126 | * @author superliuliuliu1 127 | * @version 1.0 128 | * @lastupdate 2018/10/09 129 | * @return sockfd 130 | */ 131 | static int setsocket(int port) { 132 | int sockfd; 133 | struct sockaddr_in server; 134 | int reuse = 1;//used in setsockopt() 135 | 136 | //对server进行初始化 137 | memset(&server, 0, sizeof(server)); 138 | server.sin_port = htons(port); 139 | server.sin_family = AF_INET; 140 | server.sin_addr.s_addr = htonl(INADDR_ANY); 141 | //创建监听socket 142 | sockfd = socket(PF_INET, SOCK_STREAM, 0); 143 | if (sockfd < 0) { 144 | error("Error on socket()"); 145 | } 146 | 147 | //设置套接字选项SO_REUSEADDR 目的在于让本地的端口号能够重用 148 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) 149 | { 150 | close(sockfd); 151 | error("Error on setsockopt()"); 152 | } 153 | 154 | //绑定sock 155 | if ((bind(sockfd, (struct sockaddr*)&server, sizeof(server))) != 0) 156 | { 157 | close(sockfd); 158 | error("Error on bind()"); 159 | } 160 | 161 | //listen设定待连接的最大数目 162 | if (listen(sockfd, LISTENQUE) < 0) 163 | { 164 | close(sockfd); 165 | error("Error on listen()"); 166 | } 167 | return sockfd; 168 | } 169 | 170 | /** 171 | * 错误处理函数:遇到错误退出程序,并输出相关的错误信息 172 | * @author superliuliuliu1 173 | * @version 1.0 174 | * @param message 错误提示信息 175 | */ 176 | void error(char *message) 177 | { 178 | perror(message); 179 | exit(1); 180 | } 181 | 182 | /** 183 | * 接受客户端发来的数据,并将当前的系统时间发送给客户端 184 | * @author superliuliuliu1 185 | * @version 1.0 186 | * @param connfd [description] 187 | */ 188 | int timenow(int connfd) 189 | { 190 | char buffer[MAXSIZE]; 191 | int recv_size; 192 | memset(buffer, 0, MAXSIZE); 193 | time_t ntime; 194 | char timestr[30]; 195 | 196 | if ((recv_size = recv(connfd, buffer, MAXSIZE, 0)) > 0) 197 | { 198 | //接受客户端输入的命令并辨别 若收到time命令则将时间封装到buffer中,并发送出去 199 | if (strcmp(buffer, "time") == 0) 200 | { 201 | printf("Receive time request\n"); 202 | ntime = time(NULL); 203 | struct tm* tm_struct = localtime(&ntime); 204 | memset(timestr, 0, 30); 205 | strftime(timestr, 30, "%Y/%m/%d %H:%M", tm_struct); 206 | printf("%s\n", timestr); 207 | send(connfd , timestr, sizeof(timestr), 0); 208 | memset(buffer, 0, MAXSIZE); 209 | } 210 | } 211 | 212 | return recv_size; 213 | } 214 | -------------------------------------------------------------------------------- /network/select.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | #define DEFAULT_PORT (unsigned short) 7341 15 | #define LISTENQUE 10 16 | #define MAXSIZE 1024 17 | #define MAX_FD 1024 18 | 19 | void error(char *message); 20 | int timenow(int connfd); 21 | 22 | //编写基于select的I/O多路复用并发time服务器 23 | int main(int argc, char** argv) 24 | { 25 | int sockfd, connfd; 26 | struct sockaddr_in client, server; 27 | unsigned short port = DEFAULT_PORT; 28 | socklen_t len = sizeof(struct sockaddr_in); 29 | int reuse = 1;//used in setsockopt() 30 | 31 | fd_set readfds;//文件描述符集合 32 | struct timeval timeout;//设置select的阻塞时间 33 | int fdset[MAX_FD]; 34 | 35 | 36 | if (argc > 2) 37 | { 38 | printf("Usage: %s [port]\n", argv[0]); 39 | printf("服务器端的默认开放端口号为7341,如果你已经设置请忽略!\n"); 40 | error("Error on input"); 41 | } 42 | if (argc > 1) { 43 | port = (unsigned short)atoi(argv[1]); 44 | } 45 | 46 | //对server进行初始化 47 | memset(&server, 0, sizeof(server)); 48 | server.sin_port = htons(port); 49 | server.sin_family = AF_INET; 50 | server.sin_addr.s_addr = htonl(INADDR_ANY); 51 | //创建监听socket 52 | sockfd = socket(PF_INET, SOCK_STREAM, 0); 53 | if (sockfd < 0) { 54 | error("Error on socket()"); 55 | } 56 | 57 | //设置套接字选项SO_REUSEADDR 目的在于让本地的端口号能够重用 58 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) 59 | { 60 | close(sockfd); 61 | error("Error on setsockopt()"); 62 | } 63 | 64 | //绑定sock 65 | if ((bind(sockfd, (struct sockaddr*)&server, sizeof(server))) != 0) 66 | { 67 | close(sockfd); 68 | error("Error on bind()"); 69 | } 70 | 71 | //listen设定待连接的最大数目 72 | if (listen(sockfd, LISTENQUE) < 0) 73 | { 74 | close(sockfd); 75 | error("Error on listen()"); 76 | } 77 | 78 | //fdset数组中的元素全部设置为-1 79 | memset(fdset, 0xff, sizeof(fdset)); 80 | //设置select函数的阻塞时间 81 | timeout.tv_sec = 1; 82 | timeout.tv_usec = 0; 83 | int ready;//select函数的返回值 84 | int i; 85 | int maxfd = 0;//为了设置的循环检测范围,该数值应该比三个文件描述符集合的值还要大1,该参数用在select之中,使select更加有效率 86 | while (true) 87 | { 88 | FD_ZERO(&readfds); 89 | //首先将监听sockfd加入到readfds中 90 | FD_SET(sockfd, &readfds); 91 | maxfd = sockfd; 92 | //检测 93 | for (i = 0; i < MAX_FD; i++) 94 | { 95 | if (fdset[i] != -1) 96 | { 97 | if (i > maxfd) 98 | { 99 | maxfd = i; 100 | } 101 | FD_SET(i, &readfds); 102 | } 103 | } 104 | 105 | ready = select(maxfd + 1, &readfds, NULL, NULL, &timeout); 106 | if (ready == -1) 107 | { 108 | //EINTR错误代表该调用被信号处理历程给中断了,select不会自动恢复,因此需要我们加以操作 109 | if (errno == EINTR) 110 | { 111 | continue; 112 | } 113 | error("Error on select()"); 114 | } 115 | else if (ready == 0) 116 | { 117 | continue; 118 | } 119 | else //代表select执行成功 120 | { 121 | if (FD_ISSET(sockfd, &readfds)) 122 | { 123 | memset(&client, 0, sizeof(client)); 124 | connfd = accept(sockfd, (struct sockaddr*)&client, &len);//接收客户端的连接 125 | if (connfd < 0) 126 | { 127 | perror("error on accept()"); 128 | break; 129 | } 130 | else if (connfd > MAX_FD) 131 | { 132 | perror("too many clients"); 133 | close(connfd); 134 | } 135 | else 136 | { 137 | printf("此时通信的客户端IP地址:%s\n", inet_ntoa(client.sin_addr)); 138 | fdset[connfd] = 0; 139 | if (connfd > maxfd) 140 | { 141 | maxfd = connfd; 142 | } 143 | } 144 | } 145 | } 146 | for (i = 0; i < MAX_FD; i++) 147 | { 148 | if (fdset[i]!=-1 && FD_ISSET(i, &readfds)) 149 | { 150 | if (timenow(i) <= 0) 151 | { 152 | fdset[i] = -1; 153 | close(i); 154 | FD_CLR(i, &readfds); 155 | } 156 | } 157 | } 158 | } 159 | return 0; 160 | } 161 | 162 | /** 163 | * 错误处理函数:遇到错误退出程序,并输出相关的错误信息 164 | * @author superliuliuliu1 165 | * @version 1.0 166 | * @param message 错误提示信息 167 | */ 168 | void error(char *message) 169 | { 170 | perror(message); 171 | exit(1); 172 | } 173 | 174 | /** 175 | * 接受客户端发来的数据,并将当前的系统时间发送给客户端 176 | * @author superliuliuliu1 177 | * @version 1.0 178 | * @param connfd [description] 179 | */ 180 | int timenow(int connfd) 181 | { 182 | char buffer[MAXSIZE]; 183 | int recv_size; 184 | memset(buffer, 0, MAXSIZE); 185 | time_t ntime; 186 | char timestr[30]; 187 | 188 | if ((recv_size = recv(connfd, buffer, MAXSIZE, 0)) > 0) 189 | { 190 | //接受客户端输入的命令并辨别 若收到time命令则将时间封装到buffer中,并发送出去 191 | if (strcmp(buffer, "time") == 0) 192 | { 193 | printf("Receive time request\n"); 194 | ntime = time(NULL); 195 | struct tm* tm_struct = localtime(&ntime); 196 | memset(timestr, 0, 30); 197 | strftime(timestr, 30, "%Y/%m/%d %H:%M", tm_struct); 198 | printf("%s\n", timestr); 199 | send(connfd , timestr, sizeof(timestr), 0); 200 | memset(buffer, 0, MAXSIZE); 201 | } 202 | 203 | //else do nothing 204 | } 205 | 206 | return recv_size; 207 | /*if (recv_size < 0) 208 | { 209 | error("Error on recv"); 210 | } 211 | if(recv_size == 0) 212 | { 213 | printf("Client disconnected"); 214 | fflush(stdout); 215 | } 216 | close(connfd);*/ 217 | } 218 | -------------------------------------------------------------------------------- /network/serverMultipro_echo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | 14 | #define DEFAULT_PORT (unsigned short) 7341 15 | #define LISTENQUE 10 16 | #define MAXSIZE 1024 17 | 18 | /** 19 | * linux 环境下实现echo服务器 本代码实现并发式的服务器 20 | * @author superliuliuliu1 21 | * @version 1.0 22 | * @date 2018/10/17 23 | */ 24 | 25 | void error(char* message); 26 | void transport(int connfd); 27 | static void sig_child(int signo); 28 | 29 | 30 | int main(int argc, char **argv) 31 | { 32 | int sockfd, connfd; 33 | struct sockaddr_in server, client; 34 | unsigned short port = DEFAULT_PORT; 35 | pid_t pid1; 36 | socklen_t len = sizeof(struct sockaddr_in); 37 | 38 | //若启动服务器时未输入端口号,则端口号设置为默认的端口号 39 | if(argc > 1){ 40 | port = (unsigned short)atoi(argv[1]); 41 | } 42 | 43 | //创建socket 44 | sockfd = socket(PF_INET, SOCK_STREAM, 0); 45 | if (sockfd < 0) 46 | { 47 | error("Error open the socket!"); 48 | } 49 | 50 | //对server相关信息进行初始化 注意字节序问题 51 | memset(&server, 0, sizeof(server)); 52 | 53 | server.sin_family = AF_INET; 54 | server.sin_port = htons(port); 55 | server.sin_addr.s_addr = htonl(INADDR_ANY); 56 | 57 | //bind()函数的返回值为0时才表示绑定成功 58 | if ((bind(sockfd, (struct sockaddr*)&server, sizeof(server))) != 0) 59 | { 60 | error("Error on bind"); 61 | } 62 | 63 | // 允许LISTENQUE个连接在队列处等待 64 | if (listen(sockfd, LISTENQUE) < 0) 65 | { 66 | error("Error on listen"); 67 | } 68 | 69 | while (true) 70 | { 71 | len = sizeof(client); 72 | if ((connfd = accept(sockfd, (struct sockaddr *)&client, &len)) < 0) 73 | { 74 | fprintf(stderr, "accept error!\n"); 75 | continue; 76 | } 77 | signal(SIGCHLD, sig_child); 78 | pid1 = fork(); 79 | switch(pid1) 80 | { 81 | case -1: 82 | { 83 | close(connfd); 84 | perror("Error on fork"); 85 | break; 86 | } 87 | case 0: 88 | { 89 | printf("此时通信的客户端IP地址:%s\n", inet_ntoa(client.sin_addr)); 90 | transport(connfd); 91 | } 92 | default: 93 | { 94 | close(connfd); 95 | break; 96 | } 97 | } 98 | 99 | } 100 | //close(sockfd); 101 | return 0; 102 | } 103 | 104 | /** 105 | * 传输函数 子进程调用该函数来进行与客户端的通信 并且通过调用exit来结束子进程 106 | * @author superliuliuliu1 107 | * @version [version] 108 | * @param connfd [description] 109 | */ 110 | void transport(int connfd) 111 | { 112 | char buffer[MAXSIZE]; 113 | int recv_size; 114 | 115 | memset(buffer, 0, MAXSIZE); 116 | while((recv_size = recv(connfd, buffer, MAXSIZE, 0)) > 0) 117 | { 118 | write(connfd , buffer, recv_size); 119 | memset(buffer, 0, MAXSIZE); 120 | } 121 | 122 | if(recv_size == 0) 123 | { 124 | printf("Client put nothing"); 125 | fflush(stdout); 126 | } 127 | else if(recv_size == -1) 128 | { 129 | error("Error on recv"); 130 | } 131 | close(connfd); 132 | exit(0); 133 | 134 | } 135 | 136 | 137 | void error(char* message) 138 | { 139 | perror(message); 140 | exit(1); 141 | } 142 | 143 | // WNOHANG 如果pid指定的子进程没有结束,则waitpid()函数立即返回0,而不是阻塞在这个函数上等待;如果结束了,则返回该子进程的进程号 144 | static void sig_child(int signo) 145 | { 146 | pid_t pid; 147 | int stat; 148 | 149 | //处理僵尸进程 150 | while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) 151 | printf("child %d terminated.\n", pid); 152 | 153 | } 154 | -------------------------------------------------------------------------------- /network/serverMultithr_echo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | #define DEFAULT_PORT (unsigned short) 7341 13 | #define LISTENQUE 10 14 | #define MAXSIZE 1024 15 | 16 | /** 17 | * linux 环境下实现echo服务器 以多线程的形式实现并发式服务器 18 | * @author superliuliuliu1 19 | * @version 1.0 20 | * @date 2018/10/17 21 | */ 22 | 23 | void error(char* message); 24 | void* transport(void* argv); 25 | 26 | 27 | int main(int argc, char **argv) 28 | { 29 | int sockfd, connfd; 30 | int *deliever; 31 | struct sockaddr_in server, client; 32 | unsigned short port = DEFAULT_PORT; 33 | socklen_t len = sizeof(struct sockaddr_in); 34 | pthread_t tid; //线程id 35 | 36 | //若启动服务器时未输入端口号,则端口号设置为默认的端口号 37 | if(argc > 1){ 38 | port = (unsigned short)atoi(argv[1]); 39 | } 40 | 41 | //创建socket 42 | sockfd = socket(PF_INET, SOCK_STREAM, 0); 43 | if (sockfd < 0) 44 | { 45 | error("Error open the socket!"); 46 | } 47 | 48 | //对server相关信息进行初始化 注意字节序问题 49 | memset(&server, 0, sizeof(server)); 50 | 51 | server.sin_family = AF_INET; 52 | server.sin_port = htons(port); 53 | server.sin_addr.s_addr = htonl(INADDR_ANY); 54 | 55 | //bind()函数的返回值为0时才表示绑定成功 56 | if ((bind(sockfd, (struct sockaddr*)&server, sizeof(server))) != 0) 57 | { 58 | error("Error on bind()"); 59 | } 60 | 61 | // 允许LISTENQUE个连接在队列处等待 62 | if (listen(sockfd, LISTENQUE) < 0) 63 | { 64 | error("Error on listen"); 65 | } 66 | 67 | while (true) 68 | { 69 | len = sizeof(client); 70 | if ((connfd = accept(sockfd, (struct sockaddr *)&client, &len)) < 0) 71 | { 72 | fprintf(stderr, "accept error!\n"); 73 | continue; 74 | } 75 | printf("此时通信的客户端IP地址:%s\n", inet_ntoa(client.sin_addr)); 76 | deliever = (int *)malloc(sizeof(int)); 77 | *deliever = connfd; 78 | pthread_create(&tid, NULL, transport, deliever); 79 | } 80 | close(sockfd); 81 | return 0; 82 | } 83 | 84 | //线程处理 85 | void* transport(void* argv) 86 | { 87 | int connfd = *((int*)argv); 88 | char buffer[MAXSIZE]; 89 | int recv_size; 90 | 91 | memset(buffer, 0, MAXSIZE); 92 | while((recv_size = recv(connfd, buffer, MAXSIZE, 0)) > 0) 93 | { 94 | write(connfd , buffer, recv_size); 95 | memset(buffer, 0, MAXSIZE); 96 | } 97 | 98 | if(recv_size == 0) 99 | { 100 | printf("Client disconnected"); 101 | fflush(stdout); 102 | } 103 | else if(recv_size == -1) 104 | { 105 | error("Error on recv"); 106 | } 107 | free(argv); 108 | close(connfd); 109 | 110 | } 111 | 112 | 113 | void error(char* message) 114 | { 115 | perror(message); 116 | exit(1); 117 | } 118 | -------------------------------------------------------------------------------- /network/server_Multiprocess_time.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | #define DEFAULT_PORT (unsigned short) 7341 15 | #define LISTENQUE 10 16 | #define MAXSIZE 1024 17 | 18 | void error(char *message); 19 | static void sig_child(int signo); 20 | void timenow(int connfd); 21 | 22 | /** 23 | * 多进程时间服务器,能够向多台客服机返回当前时间 在本程序之中,当有连接出现后,服务器接收客户端发来的信息并判断,若收到是time则返回时间。 24 | * @author superliuliuliu1 25 | * @version 1.0 26 | */ 27 | 28 | int main(int argc, char **argv) 29 | { 30 | int sockfd, connfd; 31 | struct sockaddr_in server, client; 32 | unsigned short port = DEFAULT_PORT; 33 | socklen_t len = sizeof(struct sockaddr_in); 34 | pid_t pid; 35 | 36 | if (argc > 2) 37 | { 38 | printf("Usage: %s [port]\n", argv[0]); 39 | printf("服务器端的默认开放端口号为7341,如果你已经设置请忽略!\n"); 40 | error("Error on input"); 41 | } 42 | 43 | if (argc > 1 ) { 44 | port = (unsigned short)atoi(argv[1]); 45 | } 46 | 47 | 48 | sockfd = socket(PF_INET, SOCK_STREAM, 0); 49 | if (sockfd < 0) 50 | { 51 | error("Error on socket"); 52 | } 53 | //初始化server信息 54 | memset(&server, 0, sizeof(server)); 55 | server.sin_port = htons(port); 56 | server.sin_family = AF_INET; 57 | server.sin_addr.s_addr = htonl(INADDR_ANY); 58 | //bind 函数 只有当绑定成功时 返回值为0 59 | if ((bind(sockfd, (struct sockaddr*)&server, sizeof(server))) != 0) 60 | { 61 | error("Error on bind"); 62 | } 63 | // 允许LISTENQUE个连接在队列处等待 64 | if (listen(sockfd, LISTENQUE) < 0) 65 | { 66 | error("Error on listen"); 67 | } 68 | while (true) 69 | { 70 | len = sizeof(client); 71 | if ((connfd = accept(sockfd, (struct sockaddr *)&client, &len)) < 0) 72 | { 73 | perror("accept"); 74 | continue; 75 | } 76 | //捕捉信号 77 | signal(SIGCHLD, sig_child); 78 | //创建子进程来处理客户端服务请求 79 | pid = fork(); 80 | switch (pid) 81 | { 82 | //fork失败 83 | case -1: 84 | { 85 | close(connfd); 86 | perror("Error on fork"); 87 | break; 88 | } 89 | //进入到子进程中,开始对请求服务 90 | case 0: 91 | { 92 | printf("此时通信的客户端IP地址:%s\n", inet_ntoa(client.sin_addr)); 93 | timenow(connfd); 94 | } 95 | //进入到父进程中, 96 | default: 97 | { 98 | close(connfd); 99 | break; 100 | } 101 | } 102 | } 103 | return 0; 104 | } 105 | 106 | 107 | /** 108 | * 错误处理函数:遇到错误退出程序,并输出相关的错误信息 109 | * @author superliuliuliu1 110 | * @version 1.0 111 | * @param message 错误提示信息 112 | */ 113 | void error(char *message) 114 | { 115 | perror(message); 116 | exit(1); 117 | } 118 | 119 | 120 | /** 121 | * 用来捕获子进程退出的消息SIGCHLD的信号处理函数 122 | * @author superliuliuliu1 123 | * @version 1.0 124 | * @lastupdate 2018/11/04 125 | * @param signo 126 | * 127 | */ 128 | static void sig_child(int signo) 129 | { 130 | pid_t pid; 131 | int stat; 132 | //处理僵尸进程 133 | while ((pid = waitpid(-1, &stat, WNOHANG)) >0) 134 | { 135 | printf("child %d terminated.\n", pid); 136 | } 137 | 138 | } 139 | 140 | /** 141 | * 接受客户端发来的数据,并将当前的系统时间发送给客户端 142 | * @author superliuliuliu1 143 | * @version 1.0 144 | * @param connfd [description] 145 | */ 146 | void timenow(int connfd) 147 | { 148 | char buffer[MAXSIZE]; 149 | int recv_size; 150 | memset(buffer, 0, MAXSIZE); 151 | time_t ntime; 152 | char timestr[30]; 153 | 154 | while ((recv_size = recv(connfd, buffer, MAXSIZE, 0)) > 0) 155 | { 156 | //接受客户端输入的命令并辨别 若收到time命令则将时间封装到buffer中,并发送出去 157 | if (strcmp(buffer, "time") == 0) 158 | { 159 | printf("Receive time request\n"); 160 | ntime = time(NULL); 161 | //将时间转换为本地时间 162 | struct tm* tm_struct = localtime(&ntime); 163 | memset(timestr, 0, 30); 164 | strftime(timestr, 30, "%Y/%m/%d %H:%M", tm_struct); 165 | printf("%s\n", timestr); 166 | //printf("%s\n", ctime(&ntime)); 167 | //snprintf(buffer, sizeof(buffer), "%.24s\r", ctime(&ntime)); 168 | send(connfd , timestr, sizeof(timestr), 0); 169 | memset(buffer, 0, MAXSIZE); 170 | } 171 | //else do nothing 172 | } 173 | 174 | if(recv_size <= 0) 175 | { 176 | printf("Client disconnected"); 177 | fflush(stdout); 178 | } 179 | close(connfd); 180 | exit(0); 181 | } 182 | -------------------------------------------------------------------------------- /network/server_Multithread_time.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define DEFAULT_PORT (unsigned short) 7341 15 | #define LISTENQUE 10 16 | #define MAXSIZE 1024 17 | 18 | void error(char *message); 19 | void* timenow(void *argv); 20 | 21 | /** 22 | * 多线程时间服务器,能够向多台客户机返回服务器当前时间 23 | * @author superliuliuliu1 24 | * @version 1.0 25 | */ 26 | 27 | int main(int argc, char **argv) 28 | { 29 | int sockfd, connfd; 30 | struct sockaddr_in server, client; 31 | unsigned short port = DEFAULT_PORT; 32 | socklen_t len = sizeof(struct sockaddr_in); 33 | pthread_t tid; 34 | int *deliever; 35 | 36 | if (argc > 2) 37 | { 38 | printf("Usage: %s [port]\n", argv[0]); 39 | printf("服务器端的默认开放端口号为7341,如果你已经设置请忽略!\n"); 40 | error("Error on input"); 41 | } 42 | 43 | if (argc > 1 ) { 44 | port = (unsigned short)atoi(argv[1]); 45 | } 46 | 47 | 48 | sockfd = socket(PF_INET, SOCK_STREAM, 0); 49 | if (sockfd < 0) 50 | { 51 | error("Error on socket"); 52 | } 53 | //初始化server信息 54 | memset(&server, 0, sizeof(server)); 55 | server.sin_port = htons(port); 56 | server.sin_family = AF_INET; 57 | server.sin_addr.s_addr = htonl(INADDR_ANY); 58 | 59 | //bind 函数 只有当绑定成功时 返回值为0 60 | if ((bind(sockfd, (struct sockaddr*)&server, sizeof(server))) != 0) 61 | { 62 | error("Error on bind"); 63 | } 64 | 65 | // 允许LISTENQUE个连接在队列处等待 66 | if (listen(sockfd, LISTENQUE) < 0) 67 | { 68 | error("Error on listen"); 69 | } 70 | 71 | while (true) 72 | { 73 | len = sizeof(client); 74 | if ((connfd = accept(sockfd, (struct sockaddr *)&client, &len)) < 0) 75 | { 76 | perror("accept"); 77 | continue; 78 | } 79 | printf("此时通信的客户端IP地址:%s\n", inet_ntoa(client.sin_addr)); 80 | //因为线程创建函数是通过一个指针来传递参数,因此需要为其分配内存空间 81 | deliever = (int*)malloc(sizeof(int)); 82 | *deliever = connfd;//将connfd传递给线程start函数 83 | if (pthread_create(&tid, NULL, timenow, deliever) != 0) 84 | { 85 | perror("Error on thread create"); 86 | } 87 | //free(deliever); 88 | } 89 | pthread_exit(NULL); 90 | return 0; 91 | } 92 | 93 | 94 | /** 95 | * 错误处理函数:遇到错误退出程序,并输出相关的错误信息 96 | * @author superliuliuliu1 97 | * @version 1.0 98 | * @param message 错误提示信息 99 | */ 100 | void error(char *message) 101 | { 102 | perror(message); 103 | exit(1); 104 | } 105 | 106 | 107 | /** 108 | * 线程start函数 109 | * @author superliuliuliu1 110 | * @version 1.0 111 | * @param connfd [description] 112 | */ 113 | void* timenow(void* argv) 114 | { 115 | char buffer[MAXSIZE]; 116 | int recv_size; 117 | memset(buffer, 0, MAXSIZE); 118 | time_t tricks; 119 | char timen[30]; 120 | int connfd = *((int*)argv); 121 | 122 | //设置在子线程终止时,自动释放其资源 123 | pthread_detach(pthread_self()); 124 | 125 | while ((recv_size = recv(connfd, buffer, MAXSIZE, 0)) > 0) 126 | { 127 | //接受客户端输入的命令并辨别 若收到time命令则将时间封装到timen中,并发送出去 128 | if (strcmp(buffer, "time") == 0) 129 | { 130 | tricks = time(NULL); 131 | struct tm* tm_struct = localtime(&tricks); 132 | printf("Receive time request\n"); 133 | memset(timen, 0, 30); 134 | strftime(timen, 30, "%Y/%m/%d %H:%M", tm_struct); 135 | printf("%s\n", timen); 136 | //printf("%s\n", ctime(&tricks)); 137 | //snprintf(buffer, sizeof(buffer), "%.24s\r", ctime(&tricks)); 138 | send(connfd , timen, sizeof(timen), 0); 139 | //memset(timen, 0, 30); 140 | memset(buffer, 0, MAXSIZE); 141 | } 142 | //else do nothing 143 | } 144 | 145 | if(recv_size <= 0) 146 | { 147 | printf("Client disconnected"); 148 | fflush(stdout); 149 | } 150 | free(argv); 151 | close(connfd); 152 | pthread_exit(NULL); 153 | } 154 | -------------------------------------------------------------------------------- /network/server_echo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | #define DEFAULT_PORT (unsigned short) 7341 12 | #define LISTENQUE 10 13 | #define MAXSIZE 1024 14 | 15 | /** 16 | * linux 环境下实现echo服务器 实现代码有两种一种迭代式的实现另一种并发式的实现 17 | * @author superliuliuliu1 18 | * @version 1.0 19 | * @date 2018/10/17 20 | */ 21 | 22 | void error(char* message); 23 | void transport(int connfd); 24 | 25 | 26 | int main(int argc, char **argv) 27 | { 28 | int sockfd, connfd; 29 | struct sockaddr_in server, client; 30 | unsigned short port = DEFAULT_PORT; 31 | socklen_t len = sizeof(struct sockaddr_in); 32 | 33 | //若启动服务器时未输入端口号,则端口号设置为默认的端口号 34 | if(argc > 1){ 35 | port = (unsigned short)atoi(argv[1]); 36 | } 37 | 38 | //创建socket 39 | sockfd = socket(PF_INET, SOCK_STREAM, 0); 40 | if (sockfd < 0) 41 | { 42 | error("Error open the socket!"); 43 | } 44 | 45 | //对server相关信息进行初始化 注意字节序问题 46 | memset(&server, 0, sizeof(server)); 47 | 48 | server.sin_family = AF_INET; 49 | server.sin_port = htons(port); 50 | server.sin_addr.s_addr = htonl(INADDR_ANY); 51 | 52 | //bind()函数的返回值为0时才表示绑定成功 53 | if ((bind(sockfd, (struct sockaddr*)&server, sizeof(server))) != 0) 54 | { 55 | error("Error on bind()"); 56 | } 57 | 58 | // 允许LISTENQUE个连接在队列处等待 59 | if (listen(sockfd, LISTENQUE) < 0) 60 | { 61 | error("Error on listen"); 62 | } 63 | 64 | while (true) 65 | { 66 | len = sizeof(client); 67 | if ((connfd = accept(sockfd, (struct sockaddr *)&client, &len)) < 0) 68 | { 69 | fprintf(stderr, "accept error!\n"); 70 | continue; 71 | } 72 | printf("此时通信的客户端IP地址:%s\n", inet_ntoa(client.sin_addr)); 73 | transport(connfd); 74 | } 75 | close(sockfd); 76 | return 0; 77 | } 78 | 79 | void transport(int connfd) 80 | { 81 | char buffer[MAXSIZE]; 82 | int recv_size; 83 | 84 | memset(buffer, 0, MAXSIZE); 85 | while((recv_size = recv(connfd, buffer, MAXSIZE, 0)) > 0) 86 | { 87 | write(connfd , buffer, recv_size); 88 | memset(buffer, 0, MAXSIZE); 89 | } 90 | 91 | if(recv_size == 0) 92 | { 93 | printf("Client disconnected"); 94 | fflush(stdout); 95 | } 96 | else if(recv_size == -1) 97 | { 98 | error("Error on recv"); 99 | } 100 | close(connfd); 101 | 102 | } 103 | 104 | 105 | void error(char* message) 106 | { 107 | perror(message); 108 | exit(1); 109 | } 110 | -------------------------------------------------------------------------------- /operation/Linux_304_1_2016220204010_刘高阳.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superliuliuliu/socketprogram/01b30440b0d4e36e236d1463d926ea507ef5fa5a/operation/Linux_304_1_2016220204010_刘高阳.docx -------------------------------------------------------------------------------- /operation/cptest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define BUFFSIZE 1024 9 | 10 | void error(char* message); 11 | 12 | int main(int argc, char** argv) 13 | { 14 | int sourcefd, destfd; 15 | struct stat s_buff;//stat结构体用来存储文件的相关属性信息 16 | char command[5]; 17 | ssize_t numread; 18 | char buffer[BUFFSIZE]; 19 | 20 | if (argc != 3 || strcmp(argv[1], "--help") == 0) 21 | { 22 | printf("使用指南\n"); 23 | printf("Usage: %s [source file path] [dest file path]\n", argv[0]); 24 | exit(0); 25 | } 26 | //判断输入的源文件是否是目录 27 | stat(argv[1], &s_buff); 28 | if (S_ISDIR(s_buff.st_mode)) 29 | { 30 | error("The source file is a directionry"); 31 | } 32 | //对应源文件不存在的情况 33 | sourcefd = open(argv[1], O_RDONLY); 34 | if (sourcefd == -1) 35 | { 36 | error("Error on find the source file"); 37 | } 38 | 39 | //判断目标文件是否存在,然后做出选择 40 | if (access(argv[2], F_OK) == 0) 41 | { 42 | printf("目标文件已经存在,输入y去拼接文件(默认直接覆盖文件)\n"); 43 | if ((fgets(command, sizeof(command), stdin)) == NULL) 44 | { 45 | error("Error on input"); 46 | } 47 | 48 | if (strcmp(command, "y\n") == 0) 49 | { 50 | //以合并的方式打开文件 51 | destfd = open(argv[2], O_WRONLY | O_APPEND); 52 | printf("将以合并的形式对文件操作\n"); 53 | if (destfd == -1) 54 | { 55 | error("Error on output"); 56 | } 57 | lseek(destfd, 0, SEEK_END);//改变文件的偏移量至文件尾部,已达到拼接的目的 58 | } 59 | else 60 | { 61 | //以覆盖的方式打开文件 62 | destfd = open(argv[2], O_WRONLY | O_TRUNC); 63 | if (destfd == -1) 64 | { 65 | error("Error on output"); 66 | } 67 | } 68 | } 69 | else 70 | { 71 | destfd = open(argv[2], O_WRONLY | O_CREAT | O_EXCL | O_TRUNC); 72 | if (destfd == -1) 73 | { 74 | error("Error on output"); 75 | } 76 | } 77 | 78 | //初始化buffer 79 | memset(buffer, 0, BUFFSIZE); 80 | 81 | while ((numread = read(sourcefd, buffer, BUFFSIZE)) > 0 ) 82 | { 83 | if (write(destfd, buffer, numread) != numread) 84 | { 85 | error("Error on write"); 86 | } 87 | } 88 | close(sourcefd); 89 | close(destfd); 90 | } 91 | 92 | /** 93 | * error 94 | * @author superliuliuliu1 95 | * @version 1.0 96 | * @param message the pointer 97 | */ 98 | void error(char *message) 99 | { 100 | perror(message); 101 | exit(1); 102 | } 103 | -------------------------------------------------------------------------------- /operation/ls_my.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | //定义一个结构体 用来存储文件的相关信息 16 | typedef struct file_info 17 | { 18 | char authority[11];//文件的权限 包括文件类型 用户权限 用户组权限 其他用户权限 19 | char *u_name;//文件所属用户名 20 | char *g_name;//文件所属用户所在用户组名 21 | char *f_name;//文件名 22 | off_t f_size;//文件大小 23 | time_t *latest_time;//最近修改时间 24 | nlink_t link_num;//文件的硬连接数 25 | 26 | }file_detail; 27 | 28 | 29 | bool listall = false; 30 | bool listlong = false; 31 | bool listlink = false; 32 | 33 | 34 | void traversal_dir(char *dir); 35 | void error(char* message); 36 | void print_info(file_detail info); 37 | char* uid_2uname(uid_t u1); 38 | char* gid_2gname(gid_t g1); 39 | 40 | 41 | /** 42 | * 实现自己的ls命令 当前只支持查看当前目录下的文件的相关信息 43 | * @author superliuliuliu1 44 | * @version 1.0 45 | * @param argc [description] 46 | * @param argv [description] 47 | * @return [description] 48 | */ 49 | int main(int argc, char **argv) 50 | { 51 | int opt_arg; 52 | char *current_dir = "."; 53 | //获取输入的 -x参数确定命令 54 | //-a 代表显示所有的文件 55 | //-d 表示显示 . 和 .. 56 | //-f 表示显示符号链接指向文件的参数 57 | //无参数的话只显示ls命令下的文件信息 58 | while ((opt_arg = getopt(argc, argv, "adf")) != -1) 59 | { 60 | switch(opt_arg) 61 | { 62 | case 'a': 63 | { 64 | listall = true; 65 | break; 66 | } 67 | case 'd': 68 | { 69 | listlong = true; 70 | break; 71 | } 72 | case 'f': 73 | { 74 | listlink = true; 75 | break; 76 | } 77 | case '?': 78 | { 79 | printf("Unkown option!\n"); 80 | printf("-a 列出目录下所有文件的相关信息\n"); 81 | printf("-d 列出当前目录.和上级目录..\n"); 82 | printf("-f 列出符号链接指向文件的文件属性\n"); 83 | break; 84 | } 85 | } 86 | } 87 | traversal_dir(current_dir); 88 | return 1; 89 | } 90 | 91 | void traversal_dir(char *dir) 92 | { 93 | DIR *dp; 94 | struct stat stat_file; 95 | struct dirent *entry;//目录的入口 96 | 97 | //打开目录 98 | if ((dp = opendir(dir)) == NULL) 99 | { 100 | error("Error on open the dir"); 101 | } 102 | //遍历目录中的文件,并打印相关信息直至到达目录结尾 103 | while ((entry = readdir(dp)) != NULL) 104 | { 105 | //扩展功能 -d 即如果不输入-d 则会跳过. 和 .. 文件 106 | if (!listlong) 107 | { 108 | if (strcmp(".", entry->d_name) == 0 || strcmp("..", entry->d_name) == 0) 109 | { 110 | continue; 111 | } 112 | } 113 | //扩展功能 -f 114 | //将文件的数据填充到stat_file中 当listlink为true时使用lstat(返回符号链接文件本身的属性),否则使用stat函数(返回符号引用文件的属性) 115 | if (!listlink) 116 | { 117 | lstat(entry->d_name, &stat_file); 118 | } 119 | else 120 | { 121 | stat(entry->d_name, &stat_file); 122 | } 123 | if (!listall) 124 | { 125 | if (entry->d_name[0] == '.'& strcmp(".", entry->d_name) != 0 & strcmp("..", entry->d_name) != 0) 126 | { 127 | continue; 128 | } 129 | } 130 | 131 | file_detail info; 132 | memset(&info, 0, sizeof(info)); 133 | //memset(info.authority, 0, 11); 134 | //将文件的类型以及权限信息转换为字符串 135 | info.authority[0] = '-'; 136 | if (S_ISDIR(stat_file.st_mode)) 137 | { 138 | info.authority[0] = 'd'; 139 | } 140 | if (S_ISCHR(stat_file.st_mode)) 141 | { 142 | info.authority[0] = 'r'; 143 | } 144 | if (S_ISBLK(stat_file.st_mode)) 145 | { 146 | info.authority[0] = 'b'; 147 | } 148 | if (S_ISFIFO(stat_file.st_mode)) 149 | { 150 | info.authority[0] = 'p'; 151 | } 152 | if (S_ISLNK(stat_file.st_mode)) 153 | { 154 | info.authority[0] = 'l'; 155 | } 156 | if (S_ISSOCK(stat_file.st_mode)) 157 | { 158 | info.authority[0] = 's'; 159 | } 160 | //进行位运算从而确定权限 161 | info.authority[1] = (stat_file.st_mode & S_IRUSR) == S_IRUSR ? 'r': '-'; 162 | info.authority[2] = (stat_file.st_mode & S_IWUSR) == S_IWUSR ? 'w': '-'; 163 | info.authority[3] = (stat_file.st_mode & S_IXUSR) == S_IXUSR ? 'x': '-'; 164 | 165 | info.authority[4] = (stat_file.st_mode & S_IRGRP) == S_IRGRP ? 'r': '-'; 166 | info.authority[5] = (stat_file.st_mode & S_IWGRP) == S_IWGRP ? 'w': '-'; 167 | info.authority[6] = (stat_file.st_mode & S_IXGRP) == S_IXGRP ? 'x': '-'; 168 | 169 | info.authority[7] = (stat_file.st_mode & S_IROTH) == S_IROTH ? 'r': '-'; 170 | info.authority[8] = (stat_file.st_mode & S_IWOTH) == S_IWOTH ? 'w': '-'; 171 | info.authority[9] = (stat_file.st_mode & S_IXOTH) == S_IXOTH ? 'x': '-'; 172 | info.authority[10] = '\0'; 173 | 174 | 175 | info.f_name = entry->d_name; 176 | info.f_size = stat_file.st_size; 177 | info.latest_time = &(stat_file.st_mtime); 178 | info.link_num = stat_file.st_nlink; 179 | info.u_name = uid_2uname(stat_file.st_uid); 180 | info.g_name = gid_2gname(stat_file.st_gid); 181 | 182 | print_info(info); 183 | } 184 | closedir(dp); 185 | 186 | } 187 | 188 | 189 | void print_info(file_detail info) 190 | { 191 | struct tm* tm_struct = localtime(info.latest_time); 192 | char time[100]; 193 | strftime(time, 100, "%h %e %H:%M", tm_struct); 194 | printf("%s ", info.authority); 195 | printf("%10s ", info.u_name); 196 | printf("%10s ", info.g_name); 197 | printf("%10ld ", info.f_size); 198 | printf("%s ", time); 199 | printf("%2ld ", info.link_num); 200 | printf("%s ", info.f_name); 201 | memset(time, 0, sizeof(time)); 202 | printf("\n"); 203 | } 204 | 205 | /** 206 | * print error message 207 | * @author superliuliuliu1 208 | * @version 1.0 209 | * @param message the pointer 210 | */ 211 | void error(char* message) { 212 | perror(message); 213 | exit(1); 214 | } 215 | 216 | /** 217 | * 根据uid查找用户名 218 | * @author superliuliuliu1 219 | * @version 1.0 220 | * @param u1 [description] 221 | * @return [description] 222 | */ 223 | char* uid_2uname(uid_t u1) 224 | { 225 | struct passwd *p; 226 | p = (struct passwd*)malloc(sizeof(struct passwd)); 227 | p = getpwuid(u1); 228 | if (p!=NULL) 229 | { 230 | return p->pw_name; 231 | } 232 | else 233 | { 234 | char *s; 235 | s = (char*)malloc(sizeof(char)*5); 236 | sprintf(s, "%d", u1); 237 | return s; 238 | } 239 | } 240 | 241 | /** 242 | * 根据gid查找用户所属组名 243 | * @author superliuliuliu1 244 | * @version 1.0 245 | * @param g1 [description] 246 | * @return [description] 247 | */ 248 | char* gid_2gname(gid_t g1) 249 | { 250 | struct group *g; 251 | g = (struct group*)malloc(sizeof(struct group)); 252 | g = getgrgid(g1); 253 | if (g!=NULL) 254 | { 255 | return g->gr_name; 256 | } 257 | else 258 | { 259 | char *s; 260 | s = (char*)malloc(sizeof(char)*5); 261 | sprintf(s, "%d", g1); 262 | return s; 263 | } 264 | 265 | } 266 | -------------------------------------------------------------------------------- /operation/process.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | //定义一个结构体 用来存储文件的相关信息 16 | typedef struct file_info 17 | { 18 | char authority[11];//文件的权限 包括文件类型 用户权限 用户组权限 其他用户权限 19 | char *u_name;//文件所属用户名 20 | char *g_name;//文件所属用户所在用户组名 21 | char *f_name;//文件名 22 | off_t f_size;//文件大小 23 | time_t *latest_time;//最近修改时间 24 | nlink_t link_num;//文件的硬连接数 25 | 26 | }file_detail; 27 | 28 | void traversal_dir(char *dir); 29 | void error(char* message); 30 | void print_info(file_detail info); 31 | char* uid_2uname(uid_t u1); 32 | char* gid_2gname(gid_t g1); 33 | void fill_file_detail(struct stat stat_file, struct dirent *entry); 34 | void docopy(struct dirent *entry1); 35 | 36 | /** 37 | * 遍历当前目录,当文件是子目录之时,创建子进程进入目录执行之前编写的cp程序复制子目录下所有文件到/home/lgy中 主进程执行ls -l即列出目录下的文件 38 | * @author superliuliuliu1 39 | * @version 1.0 40 | * @lastupdate 2018/11/7 41 | * @param 42 | * @param 43 | * @return 44 | */ 45 | int main(int argc, char **argv) 46 | { 47 | char *current_dir = "."; 48 | traversal_dir(current_dir); 49 | return 1; 50 | } 51 | 52 | void traversal_dir(char *dir) 53 | { 54 | DIR *dp; 55 | struct stat stat_file; 56 | struct dirent *entry;//目录的入口 57 | pid_t pid; 58 | 59 | //打开目录 60 | if ((dp = opendir(dir)) == NULL) 61 | { 62 | error("Error on open the dir"); 63 | } 64 | //遍历目录中的文件,并打印相关信息直至到达目录结尾 65 | while ((entry = readdir(dp)) != NULL) 66 | { //默认返回链接文件原文件的属性 67 | lstat(entry->d_name, &stat_file); 68 | //打印文件信息 69 | fill_file_detail(stat_file, entry); 70 | //判断文件是否是目录,如果不是则跳过 71 | if (!S_ISDIR(stat_file.st_mode)) 72 | { 73 | continue; 74 | } 75 | if (strcmp(".", entry->d_name) == 0 || strcmp("..", entry->d_name) == 0) 76 | { 77 | continue; 78 | } 79 | DIR* childdp; 80 | struct stat stat_file1; 81 | struct dirent* entry1; 82 | //打开目录 传进来的参数文件名为子目录文件名 83 | if ((childdp = opendir(entry->d_name)) == NULL) 84 | { 85 | error("Error on open the dir"); 86 | } 87 | //遍历目录中的文件,并打印相关信息直至到达目录结尾,这里的每一个目录项为子目录里的每一个文件 88 | while ((entry1 = readdir(childdp)) != NULL) 89 | { 90 | //跳过子目录里的.和..文件 91 | if (strcmp(".", entry1->d_name) == 0 || strcmp("..", entry1->d_name) == 0) 92 | { 93 | continue; 94 | } 95 | char path[50]; 96 | memset(path, 0, sizeof(path)); 97 | getcwd(path, 50); 98 | char name[100]; 99 | memset(name, 0, sizeof(name)); 100 | sprintf(name, "%s/%s/%s", path, entry->d_name, entry1->d_name); 101 | 102 | char name2[100]; 103 | memset(name2, 0, sizeof(name2)); 104 | sprintf(name2, "/home/liugaoyang/%s", entry1->d_name); 105 | 106 | pid = fork(); 107 | switch(pid) 108 | { 109 | case -1: 110 | { 111 | error("Error on fork");//因为这里直接退出程序所以不用break 112 | } 113 | case 0: 114 | { 115 | printf("子进程工作中....\n");//一个子进程只处理一个文件的复制工作 116 | printf("copy file %s to /home/liugaoyang/ ...\n", entry1->d_name); 117 | execl("/root/linux/copy", "copy", name, name2, NULL); 118 | } 119 | default: 120 | { 121 | //wait()也可以,waitpid中第三个参数为0的话 代表主进程会阻塞直至子进程完成工作 122 | //除此之外还有两个参数WNOHANG 代表如果pid指定的子进程还没有结束,则函数立即返回0而不是阻塞在这个函数上等待,如果结束了则返回子进程的进程号 123 | //WUNTRACED 如果子进程进入暂停状态,马上返回 124 | waitpid(pid, NULL, 0); 125 | printf("子进程执行的操作已经完成\n"); 126 | break; 127 | } 128 | } 129 | } 130 | closedir(childdp); 131 | } 132 | closedir(dp); 133 | } 134 | 135 | /** 136 | * [print_info description] 137 | * @author superliuliuliu1 138 | * @version [version] 139 | * @lastupdate {[date]} 140 | * @param info [description] 141 | */ 142 | void print_info(file_detail info) 143 | { 144 | struct tm* tm_struct = localtime(info.latest_time); 145 | char time[100]; 146 | strftime(time, 100, "%h %e %H:%M", tm_struct); 147 | printf("%s ", info.authority); 148 | printf("%10s ", info.u_name); 149 | printf("%10s ", info.g_name); 150 | printf("%10ld ", info.f_size); 151 | printf("%s ", time); 152 | printf("%2ld ", info.link_num); 153 | printf("%s ", info.f_name); 154 | memset(time, 0, sizeof(time)); 155 | printf("\n"); 156 | } 157 | 158 | /** 159 | * print error message 160 | * @author superliuliuliu1 161 | * @version 1.0 162 | * @param message the pointer 163 | */ 164 | void error(char* message) { 165 | perror(message); 166 | exit(1); 167 | } 168 | 169 | /** 170 | * 根据uid查找用户名 171 | * @author superliuliuliu1 172 | * @version 1.0 173 | * @param u1 [description] 174 | * @return [description] 175 | */ 176 | char* uid_2uname(uid_t u1) 177 | { 178 | struct passwd *p; 179 | p = (struct passwd*)malloc(sizeof(struct passwd)); 180 | p = getpwuid(u1); 181 | if (p != NULL) 182 | { 183 | return p->pw_name; 184 | } 185 | else 186 | { 187 | char *s; 188 | s = (char*)malloc(sizeof(char)*5); 189 | sprintf(s, "%d", u1); 190 | return s; 191 | } 192 | } 193 | 194 | /** 195 | * 根据gid查找用户所属组名 196 | * @author superliuliuliu1 197 | * @version 1.0 198 | * @param g1 [description] 199 | * @return [description] 200 | */ 201 | char* gid_2gname(gid_t g1) 202 | { 203 | struct group *g; 204 | g = (struct group*)malloc(sizeof(struct group)); 205 | g = getgrgid(g1); 206 | if (g != NULL) 207 | { 208 | return g->gr_name; 209 | } 210 | else 211 | { 212 | char *s; 213 | s = (char*)malloc(sizeof(char)*5); 214 | sprintf(s, "%d", g1); 215 | return s; 216 | } 217 | } 218 | 219 | /** 220 | * 将文件的信息填充到文件结构体中,并打印相关信息 221 | * @author superliuliuliu1 222 | * @version 1.0 223 | * @lastupdate 2018/11/7 224 | * @param stat_file [description] 225 | */ 226 | void fill_file_detail(struct stat stat_file, struct dirent *entry) 227 | { 228 | file_detail info; 229 | memset(&info, 0, sizeof(info)); 230 | //将文件的类型以及权限信息转换为字符串 231 | info.authority[0] = '-'; 232 | if (S_ISDIR(stat_file.st_mode)) 233 | { 234 | info.authority[0] = 'd'; 235 | } 236 | if (S_ISCHR(stat_file.st_mode)) 237 | { 238 | info.authority[0] = 'r'; 239 | } 240 | if (S_ISBLK(stat_file.st_mode)) 241 | { 242 | info.authority[0] = 'b'; 243 | } 244 | if (S_ISFIFO(stat_file.st_mode)) 245 | { 246 | info.authority[0] = 'p'; 247 | } 248 | if (S_ISLNK(stat_file.st_mode)) 249 | { 250 | info.authority[0] = 'l'; 251 | } 252 | if (S_ISSOCK(stat_file.st_mode)) 253 | { 254 | info.authority[0] = 's'; 255 | } 256 | //进行位运算从而确定权限 257 | info.authority[1] = (stat_file.st_mode & S_IRUSR) == S_IRUSR ? 'r': '-'; 258 | info.authority[2] = (stat_file.st_mode & S_IWUSR) == S_IWUSR ? 'w': '-'; 259 | info.authority[3] = (stat_file.st_mode & S_IXUSR) == S_IXUSR ? 'x': '-'; 260 | 261 | info.authority[4] = (stat_file.st_mode & S_IRGRP) == S_IRGRP ? 'r': '-'; 262 | info.authority[5] = (stat_file.st_mode & S_IWGRP) == S_IWGRP ? 'w': '-'; 263 | info.authority[6] = (stat_file.st_mode & S_IXGRP) == S_IXGRP ? 'x': '-'; 264 | 265 | info.authority[7] = (stat_file.st_mode & S_IROTH) == S_IROTH ? 'r': '-'; 266 | info.authority[8] = (stat_file.st_mode & S_IWOTH) == S_IWOTH ? 'w': '-'; 267 | info.authority[9] = (stat_file.st_mode & S_IXOTH) == S_IXOTH ? 'x': '-'; 268 | info.authority[10] = '\0'; 269 | 270 | info.f_name = entry->d_name; 271 | info.f_size = stat_file.st_size; 272 | info.latest_time = &(stat_file.st_mtime); 273 | info.link_num = stat_file.st_nlink; 274 | info.u_name = uid_2uname(stat_file.st_uid); 275 | info.g_name = gid_2gname(stat_file.st_gid); 276 | print_info(info); 277 | } 278 | 279 | 280 | /** 281 | * 对目录文件中文件进行copy操作 282 | * @author superliuliuliu1 283 | * @version [version] 284 | * @lastupdate {[date]} 285 | * @param catalog [description] 286 | */ 287 | void docopy(struct dirent *entry1) 288 | { 289 | DIR* childdp; 290 | struct stat stat_file; 291 | struct dirent* entry; 292 | 293 | //打开目录 传进来的参数文件名为子目录文件名 294 | if ((childdp = opendir(entry1->d_name)) == NULL) 295 | { 296 | error("Error on open the dir"); 297 | } 298 | //遍历目录中的文件,并打印相关信息直至到达目录结尾 299 | while ((entry = readdir(childdp)) != NULL) 300 | { 301 | if (strcmp(".", entry->d_name) == 0 || strcmp("..", entry->d_name) == 0) 302 | { 303 | continue; 304 | } 305 | //lstat(entry->d_name, &stat_file); 306 | char path[50]; 307 | memset(path, 0, sizeof(path)); 308 | getcwd(path, 50); 309 | char name[100]; 310 | memset(name, 0, sizeof(name)); 311 | sprintf(name, "%s/%s/%s", path, entry1->d_name, entry->d_name); 312 | //printf("%s\n", name); 313 | 314 | char name2[100]; 315 | memset(name2, 0, sizeof(name2)); 316 | sprintf(name2, "/home/liugaoyang/%s", entry->d_name); 317 | 318 | printf("copy file %s to /home/liugaoyang/ ...\n", entry->d_name); 319 | execl("/root/linux/copy", "copy", name, name2, NULL); 320 | printf("exiting child process ----\n"); 321 | printf("test"); 322 | 323 | } 324 | 325 | closedir(childdp); 326 | exit(0); 327 | } 328 | --------------------------------------------------------------------------------