标签:
最近偶尔有时间,研究了下Socket的使用,虽然不简单,不过还是挺有意思,刚好咱们带头大哥需要我们发檄文,也罢,那就来一篇,废话不多说,直接入正题
struct sockaddr_in server_addr; pthread_mutex_t mut; struct kevent events[10];
//IP地址、端口和协议族 server_addr.sin_len = sizeof(struct sockaddr_in); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(SERVER_PORT); server_addr.sin_addr.s_addr = inet_addr(ipAddress); bzero(&(server_addr.sin_zero),8);
//创建socket int server_sock_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_sock_fd == -1) { perror("socket error"); return NULL; } int on=1; if((setsockopt(server_sock_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))<0) { perror("setsockopt failed"); exit(EXIT_FAILURE); } //绑定socket int bind_result = bind(server_sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)); if (bind_result == -1) { perror("bind error"); return NULL; } //监听 if (listen(server_sock_fd, BACKLOG) == -1) { perror("listen error"); return NULL; } struct timespec timeout = {10,0}; //kqueue int kq = kqueue(); if (kq == -1) { perror("创建kqueue出错!\n"); exit(1); }
struct kevent event_change; EV_SET(&event_change, STDIN_FILENO, EVFILT_READ, EV_ADD, 0, 0, NULL); kevent(kq, &event_change, 1, NULL, 0, NULL); EV_SET(&event_change, server_sock_fd, EVFILT_READ, EV_ADD, 0, 0, NULL); kevent(kq, &event_change, 1, NULL, 0, NULL); while (1) { int ret = kevent(kq, NULL, 0, events, 10, &timeout); if (ret < 0) { printf("kevent 出错!\n"); continue; }else if(ret == 0){ printf("kenvent 超时!\n"); continue; }else{ //ret > 0 返回事件放在events中 for (int i = 0; i < ret; i++) { struct kevent current_event = events[i]; //kevent中的ident就是文件描述符 if (current_event.ident == STDIN_FILENO) { //标准输入 bzero(input_msg, BUFFER_SIZE); fgets(input_msg, BUFFER_SIZE, stdin); //输入 ".quit" 则退出服务器 if (strcmp(input_msg, QUIT_CMD) == 0) { exit(0); } for (int i=0; i<CONCURRENT_MAX; i++) { if (client_fds[i]!=0) { send(client_fds[i], input_msg, BUFFER_SIZE, 0); } } }else if(current_event.ident == server_sock_fd){ //有新的连接请求 struct sockaddr_in client_address; socklen_t address_len; int client_socket_fd = accept(server_sock_fd, (struct sockaddr *)&client_address, &address_len); if (client_socket_fd > 0) { int index = -1; for (int i = 0; i < CONCURRENT_MAX; i++) { if (client_fds[i] == 0) { index = i; client_fds[i] = client_socket_fd; break; } } if (index >= 0) { EV_SET(&event_change, client_socket_fd, EVFILT_READ, EV_ADD, 0, 0, NULL); kevent(kq, &event_change, 1, NULL, 0, NULL); printf("新客户端(fd = %d)加入成功 %s:%d \n",client_socket_fd,inet_ntoa(client_address.sin_addr),ntohs(client_address.sin_port)); /*客户端赋值*/ strcpy(client.ipAddress, inet_ntoa(client_address.sin_addr)); client.client_port = ntohs(client_address.sin_port); client.client_ID = client_socket_fd; /*收集客户端信息并且存储到列表中*/ // if (AddClient(client, &clientList) == false) { // fprintf(stderr, "Problem allcating memory\n"); // break; // } // if(ListIsFull(&clientList)) // { // puts("The list is now full.\n"); // break; // } // if(ListIsEmpty(&clientList)) // { // printf("NO client Connection"); // }else // { // Traverse(&clientList, showClients); // } // printf("在线客户端人数:%d\n", ListClientCount(&clientList)); if(!QueueIsFull(&line)) { client.client_ID = client_socket_fd; client.client_port = ntohs(client_address.sin_port); strcpy(client.ipAddress, inet_ntoa(client_address.sin_addr)); EnQueue(client, &line); //将客户端添加到队列中 char msg[250]; char wellcome[250]; sprintf(msg,"新客户端(fd = %d) 加入成功 %s:%d",client_socket_fd,inet_ntoa(client_address.sin_addr),ntohs(client_address.sin_port)); sprintf(wellcome, "WellComm To NB Socket Server System your fd is %d addr is %s and port is %d",client_socket_fd,inet_ntoa(client_address.sin_addr),ntohs(client_address.sin_port)); //给所有客户端发送消息,除了刚刚连接上的客户端之外 for(int i=0; i<QueueItemCount(&line); i++) { if(index != i) { send(client_fds[i], msg, BUFFER_SIZE, 0); }else { send(client_fds[i], wellcome, BUFFER_SIZE, 0); } } } }else{ bzero(input_msg, BUFFER_SIZE); strcpy(input_msg, "服务器加入的客户端数达到最大值,无法加入!\n"); send(client_socket_fd, input_msg, BUFFER_SIZE, 0); printf("客户端连接数达到最大值,新客户端加入失败 %s:%d \n",inet_ntoa(client_address.sin_addr),ntohs(client_address.sin_port)); } } }else{ //处理某个客户端过来的消息 bzero(recv_msg, BUFFER_SIZE); long byte_num = recv((int)current_event.ident,recv_msg,BUFFER_SIZE,0); if (byte_num > 0) { if (byte_num > BUFFER_SIZE) { byte_num = BUFFER_SIZE; } recv_msg[byte_num] = ‘\0‘; printf("客户端(fd = %d):%s\n",(int)current_event.ident,recv_msg); char delims[] = " "; char *result = NULL; result = strtok(recv_msg, delims); int k = 0; while( result != NULL ) { if(k==0) { strcpy(tableName, result); }else if (k == 1) { strcpy(userID, result); } k++; printf( "result is \"%s\n", result ); result = strtok( NULL, delims ); } sendMessage(client_fds[0], tableName, userID, user, &line); break; }else if(byte_num < 0){ printf("从客户端(fd = %d)接受消息出错.\n",(int)current_event.ident); }else{ EV_SET(&event_change, current_event.ident, EVFILT_READ, EV_DELETE, 0, 0, NULL); kevent(kq, &event_change, 1, NULL, 0, NULL); close((int)current_event.ident); for (int i = 0; i < CONCURRENT_MAX; i++) { if (client_fds[i] == (int)current_event.ident) { Client *exitClient = (Client *)malloc(sizeof(Client)); exitClient->client_ID = (int)current_event.ident; // selectClientWithFds((int)current_event.ident, &line); // int count = selectAllCilent(&line);//查找所有在线客户端 // bool del = deleteClientFormList(&clientList, *exitClient); // printf("%d\n",del); // Traverse(&clientList, showClients); // if(!ListIsEmpty(&clientList)) // { // printf("\n排序后的元素\n"); // int desc = DescClientFromList(&clientList); // Traverse(&clientList, showClients); // printf("\n逆置后的元素\n"); // Reverse(&clientList); // Traverse(&clientList, showClients); // } // printf("在线客户端人数:%d\n", ListClientCount(&clientList)); printf("客户端(fd = %d)退出了\n",(int)current_event.ident); // printf("剩余在线客户端个数%d\n",count); client_fds[i] = 0; break; } } } } } } } return NULL; } void showClients(Client client) { // printf("客户端 IP: %s, port is %d, fds is %d\n",client.ipAddress, client.port, client.fds); } //void sendClientStates(int clientCount,Queue *pq) //{ // // //} //对接收到的服务端消息进行处理,并且进行回应 void * sendMessage(int client_fds, char * message, char *userID, struct userTableInfo *userInfo, Queue *pq) { struct userMessage user = selectUserInfoWithUserID(message, userID); printf("username is %s\n", user.name); send(client_fds, user.name, BUFFER_SIZE, 0); send(client_fds, user.user_id, BUFFER_SIZE, 0); send(client_fds, user.birthday, BUFFER_SIZE, 0); // pthread_mutex_unlock(&mut); return NULL; }
以上是服务端部分代码,服务端将上线的客户端加入到链表中进行管理,当客户端上线时,服务端根据Socket的消息将客户端有关信息加入到链表中。
由于所有操作都在同一台计算机中,所以IP地址都是相同的
下面通过客户端对服务端发送相关指令获取对应的用户信息,该操作是基于客户端的指令,然后服务端通过相应指令对数据库进行查询,由于时间问题,目前该项目还不是很完善。
由于代码都是基于C语言,可以在linux, mac, windows等环境运行。
待续。。。。
标签:
原文地址:http://www.cnblogs.com/sixindev/p/4468893.html