linux套接字编程练习之网络选课模拟
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux套接字编程练习之网络选课模拟相关的知识,希望对你有一定的参考价值。
1 /**************************************** 2 > File Name:server.c 3 > Author:xiaoxiaohui 4 > mail:[email protected] 5 > Created Time:2016年05月15日 星期日 16时06分03秒 6 ****************************************/ 7 8 #include<stdio.h> 9 #include<stdlib.h> 10 #include<sys/types.h> 11 #include<sys/socket.h> 12 #include<unistd.h> 13 #include <arpa/inet.h> 14 #include<netinet/in.h> 15 #include<fcntl.h> 16 #include<string.h> 17 #include<fcntl.h> 18 #include<pthread.h> 19 20 #define LEN 1024 21 const int PORT = 8080; 22 int listenSock, linkSock; 23 struct sockaddr_in lockal; 24 struct sockaddr_in client; 25 char buf[LEN]; 26 pthread_t tid; 27 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; //互斥锁 因为buf是全局的,所以只能有一个线程访问buf 28 29 30 void ListenSock() //建立一个监听套接字 31 { 32 listenSock = socket(AF_INET, SOCK_STREAM, 0); //返回一个文件描述符 33 34 lockal.sin_family = AF_INET; 35 lockal.sin_addr.s_addr = htonl(INADDR_ANY); //适合多网卡 36 lockal.sin_port = htons(PORT); 37 38 int on = 1; 39 if( (setsockopt(listenSock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) //容许端口重用 40 { 41 perror("setsockopt "); 42 exit(EXIT_FAILURE); 43 } 44 45 if( bind(listenSock, (struct sockaddr*)&lockal, sizeof(lockal)) < 0) //绑定本地地址 46 { 47 perror("bind"); 48 exit(0); 49 } 50 51 if( listen(listenSock, 5) < 0) //进入监听状态 52 { 53 perror("listen"); 54 exit(1); 55 } 56 } 57 58 int LinkSock() //返回一个已链接套接字 59 { 60 int size = sizeof(lockal); 61 linkSock = accept(listenSock, (struct sockaddr*)&client, &size); //创建一个已链接套接字 62 if(linkSock < 0) 63 { 64 perror("accept"); 65 return -1; 66 } 67 68 return linkSock; 69 } 70 71 int checkUser(char* ptr) //判断文件中是否有字符串ptr 有则返回1 无则返回0 72 { 73 if(ptr == NULL) 74 { 75 printf("checkUser parameter is error\n"); 76 return -1; 77 } 78 79 while(*ptr != ‘ ‘ ) 80 { 81 ptr++; 82 } 83 ptr++; //此时ptr指向用户名 84 85 FILE* fp = fopen("message.txt", "r"); 86 if(fp == NULL) 87 { 88 printf("fopen is error!\n"); 89 exit(3); 90 } 91 char* message = NULL; 92 char buf[LEN]; 93 while( (message = fgets(buf, LEN, fp)) != NULL) 94 { 95 if( strstr(message, ptr) != NULL) //判断ptr是否为message的子串 96 { 97 fclose(fp); 98 return 1; 99 } 100 } 101 fclose(fp); 102 printf("there is not exist this user!\n"); 103 return 0; 104 } 105 106 int checkMode(char* ptr) //检查命令格式 如果返回1则代表格式正确 否则格式错误 107 { 108 if(ptr == NULL) 109 { 110 printf("checkMode parameter is error\n"); 111 return -1; 112 } 113 114 int count = 0; 115 while(*ptr != ‘\0‘) // 判断ptr中有多少个空格字符 116 { 117 if(*ptr == ‘ ‘) 118 { 119 count++; 120 } 121 ptr++; 122 } 123 return count; 124 } 125 126 void setcourse() 127 { 128 if( checkMode(buf) == 1) //如果只存在一个空格符则命令格式匹配 129 { 130 if( checkUser(buf) == 1) //用户名存在 说明已经选择了课程 131 { 132 char message[] = "301 User exist"; 133 write(linkSock, message, strlen(message)); 134 } 135 else //用户名不存在,说明还没选择课程 136 { 137 FILE* fp = fopen("message.txt", "a"); //以追加的方式打开文件 138 fputs(buf,fp); //把命令和用户名写到文件中 139 140 int root = 0; // 以linux为参考 0表示超级用户 1表示普通用户 141 root = rand() % 1; //随机生成0或1 142 if(root == 0) 143 { 144 fputc(‘0‘, fp); 145 } 146 else 147 { 148 fputc(‘1‘, fp); 149 } 150 fputc(‘\n‘, fp); //一行只写一个内容 151 152 char message[] = "300 OK"; 153 write(linkSock, message, strlen(message)); 154 155 while(1) //把客户端发来的课程写到文件中 156 { 157 int ret = 0; 158 memset(buf, ‘\0‘, LEN); 159 ret = read(linkSock, buf, LEN); 160 buf[ret] = ‘\0‘; 161 162 fputs(buf, fp); 163 fputc(‘\n‘, fp); 164 165 if( strcmp(buf, ".") == 0) 166 { 167 break; 168 } 169 } 170 171 fclose(fp); 172 } 173 } 174 else //命令格式不匹配 175 { 176 char message[] = "300 Message format error"; 177 write(linkSock, message, strlen(message)); 178 } 179 180 } 181 182 void getcourse() 183 { 184 char* username = buf; 185 while(*username != ‘ ‘) 186 { 187 username++; 188 } 189 username++; //此时username指向用户名 190 191 if( checkMode(buf) == 1) //如果只存在一个空格符则命令格式匹配 192 { 193 if( checkUser(buf) == 0) //用户名不存在 194 { 195 char message[] = "401 User does not exist"; 196 write(linkSock, message, strlen(message)); 197 } 198 else //用户名存在,说明选择了课程 199 { 200 FILE* fp = fopen("message.txt", "r"); //以读的方式打开文件 201 char message[] = "200 OK"; 202 write(linkSock, message, strlen(message)); 203 204 char* content = NULL; 205 while( (content = fgets(buf, LEN, fp)) != NULL) //把课程传到客户端 206 { 207 if( strstr(content, username) != NULL) //如果读到一行中的子字符串与用户名相同,则把接下来的字符串传到客户端 208 { 209 memset(buf, ‘\0‘, LEN); 210 while(fgets(buf, LEN, fp) != NULL) //把接下来的字符串传到客户端 211 { 212 write(linkSock, buf, strlen(buf)); 213 if(strstr(buf, ".") == 0) //如果遇到 . 则代表课程已经传送完 214 { 215 memset(buf, ‘\0‘, LEN); 216 break; 217 } 218 memset(buf, ‘\0‘, LEN); 219 } 220 221 break; 222 } 223 } 224 } 225 } 226 } 227 228 void ShutDown() 229 { 230 if( checkMode(buf) == 1) //如果只存在一个空格符则命令格式匹配 231 { 232 char* message = NULL; 233 char buf[LEN]; 234 FILE* fp = fopen("message.txt", "r"); 235 236 char* username = buf; 237 while(*username != ‘ ‘) 238 { 239 username++; 240 } 241 username++; //此时username指向用户名 242 243 while( (message = fgets(buf, LEN, fp)) != NULL) 244 { 245 if( strstr(message, username) != NULL) //找到有此用户的一行 然后看用户后面的权限 246 { 247 if( strchr(message, ‘0‘) != NULL) //权限为超级权限,则可以关闭服务器 248 { 249 fclose(fp); 250 exit(11); 251 } 252 else 253 { 254 break; 255 } 256 } 257 } 258 259 fclose(fp); 260 char mes[] = "201 user not allowed to execute this command"; //其它情况都是没有权限关闭服务器 261 write(linkSock, mes, strlen(mes)); 262 263 } 264 else //命令格式不匹配 265 { 266 char message[] = "300 Message format error"; 267 write(linkSock, message, strlen(message)); 268 } 269 } 270 271 void pthread(int count) 272 { 273 // pthread_detach(pthread_self()); 274 // while(1) 275 { 276 // pthread_mutex_lock(&lock); //加锁 因为buf是一个全局变量,也可以把buf改为局部变量, 然后把buf传给 277 // 相应的函数,这样就可以不用加锁,性能更高,此处就不改了 278 // int ret = 0; 279 // ret = read(linkSock, buf, LEN); 280 // if(ret < 0) 281 // { 282 // perror("read"); 283 // continue; 284 // } 285 // buf[ret] = ‘\0‘; 286 // printf("%s\n", buf); 287 288 if(strstr(buf, "SETCOURSE") != NULL) 289 { 290 setcourse(); 291 close(linkSock); //关闭链接 292 // break; 293 } 294 else if(strstr(buf, "GETCOURSE") != NULL) 295 { 296 getcourse(); 297 close(linkSock); //关闭链接 298 // break; 299 } 300 else if(strstr(buf, "SHUTDOWN") != NULL) 301 { 302 ShutDown(); 303 close(linkSock); //关闭链接 304 // break; 305 } 306 307 // pthread_mutex_unlock(&lock); 308 } 309 310 printf("the %dth of user exit!\n",count); 311 return NULL; 312 } 313 314 int main() 315 { 316 ListenSock(); //进入监听状态 317 318 int count = 1; //用户链接数 319 while(1) 320 { 321 if( LinkSock() >= 0) //文件描述符从0开始 322 { 323 int ret = 0; 324 ret = read(linkSock, buf, LEN); 325 if(ret < 0) 326 { 327 perror("read"); 328 continue; 329 } 330 buf[ret] = ‘\0‘; 331 printf("%s\n", buf); 332 333 // int error = pthread_create(&tid, NULL, pthread, (void*)count); 334 // if( error != 0 ) //创建线程失败则继续等待链接请求 335 // { 336 // printf("pthread_create is error\n"); 337 // continue; 338 // } 339 340 pthread(count); 341 count++; 342 343 // if( pthread_join(tid, NULL) == 0) //等待线程终止 不能用pthread_join因为它是阻塞式的等待 344 // { //从而会停在这不会往下继续执行,就满足不了多用户同时存在 345 // printf("the %dth of user exit!\n"); 346 // } 347 } 348 } 349 350 return 0; 351 } 352 353 354 355
1 /**************************************** 2 > File Name:client.c 3 > Author:xiaoxiaohui 4 > mail:[email protected] 5 > Created Time:2016年05月15日 星期日 16时48分21秒 6 ****************************************/ 7 8 9 #include<stdio.h> 10 #include<stdlib.h> 11 #include<sys/types.h> 12 #include<sys/socket.h> 13 #include<unistd.h> 14 #include <arpa/inet.h> 15 #include<netinet/in.h> 16 #include<fcntl.h> 17 #include<string.h> 18 #include<fcntl.h> 19 const int PORT = 8080; 20 const int LEN = 1024; 21 struct sockaddr_in server; 22 int clientSock; 23 24 25 void LinkSock() //创建一个以链接套接字 26 { 27 clientSock = socket(AF_INET, SOCK_STREAM, 0); 28 29 server.sin_family = AF_INET; 30 server.sin_addr.s_addr = inet_addr("127.0.0.1"); 31 server.sin_port = htons(PORT); 32 if( connect(clientSock, (struct sockaddr*)&server, sizeof(server)) < 0) 33 { 34 perror("connect"); 35 exit(0); 36 } 37 else 38 { 39 printf("connect success! ip:%d port:%d\n", server.sin_addr.s_addr, PORT); 40 } 41 } 42 43 int main() 44 { 45 printf("........................................................\n"); 46 printf("........................................................\n"); 47 printf("............... you can chose ................\n"); 48 printf("............... GETCOURSE ................\n"); 49 printf("............... SETCOURSE ................\n"); 50 printf("............... SHUTDOWN ................\n"); 51 printf("........................................................\n"); 52 printf("........................................................\n"); 53 54 char buf[LEN]; 55 56 while(1) 57 { 58 LinkSock(); //得到一个已链接套接字 59 60 int ret = 0; 61 printf("请选择->"); 62 // scanf("%[^\n]", &buf); //%s 不能接受有空格的字符串 或者用gets函数 63 gets(buf); 64 65 write(clientSock, buf, strlen(buf)); //把选择的命令发到服务器 66 67 memset(buf, ‘\0‘, LEN); 68 ret = read(clientSock, buf, LEN - 1 ); //接受服务器的信息 69 buf[ret] = ‘\0‘; 70 printf("%s", buf); 71 printf("\n"); 72 73 if(strstr(buf, "300 OK") != NULL) 74 { 75 while(1) 76 { 77 printf("请输入课程名->"); 78 gets(buf); 79 write(clientSock, buf, strlen(buf)); 80 if(strcmp(buf, ".") == 0) //如果是 . 则课程发送完毕 退出循环 81 { 82 break; 83 } 84 85 memset(buf, ‘\0‘, LEN); 86 } 87 88 close(clientSock); 89 memset(buf, ‘\0‘, LEN); 90 } 91 else if(strstr(buf, "200 OK") != NULL) 92 { 93 while(1) 94 { 95 memset(buf, ‘\0‘,LEN); 96 ret = read(clientSock, buf, LEN - 1 ); //接受服务器的信息 97 buf[ret] = ‘\0‘; 98 printf("%s", buf); 99 printf("\n"); 100 if(strstr(buf, ".") == 0) 101 { 102 memset(buf, ‘\0‘, LEN); 103 break; 104 } 105 } 106 107 close(clientSock); 108 } 109 } 110 111 112 return 0; 113 } 114
本文出自 “水仙花” 博客,请务必保留此出处http://10704527.blog.51cto.com/10694527/1774540
以上是关于linux套接字编程练习之网络选课模拟的主要内容,如果未能解决你的问题,请参考以下文章