Socket 基础编程(三)
来源:互联网 发布:linux下java编程工具 编辑:程序博客网 时间:2024/06/05 19:45
在上一篇文章中,我们已经采用了select式非阻塞socket进行处理,可是在实测中发现,业务处理速率依旧低下,很多connect请求超时。
通过分析发现,问题原因实际是由于socket的状态造成的。
对于TCP链接而言,默认状态下,无论是accept还是recv与send都是阻塞态,即需要收到数据包或者完成其动作,处理线程才能进行下一步工作。
知道了上述原理,那如何才能解决呢?
答案就是:fcntl
int fcntl(int fd, int cmd, struct flock *lock)
参数fd
参数fd代表欲设置的文件描述符。
参数cmd
参数cmd代表打算操作的指令。
有以下几种情况:
F_DUPFD用来查找大于或等于参数arg的最小且仍未使用的文件描述符,并且复制参数fd的文件描述符。执行成功则返回新复制的文件描述符。新描述符与fd共享同一文件表项,但是新描述符有它自己的一套文件描述符标志,其中FD_CLOEXEC文件描述符标志被清除。请参考dup2()。
F_GETFD取得close-on-exec旗标。若此旗标的FD_CLOEXEC位为0,代表在调用exec()相关函数时文件将不会关闭。
F_SETFD 设置close-on-exec 旗标。该旗标以参数arg 的FD_CLOEXEC位决定。
F_GETFL 取得文件描述符状态旗标,此旗标为open()的参数flags。
F_SETFL 设置文件描述符状态旗标,参数arg为新旗标,但只允许O_APPEND、O_NONBLOCK和O_ASYNC位的改变,其他位的改变将不受影响。
F_GETLK 取得文件锁定的状态。
F_SETLK 设置文件锁定的状态。此时flcok 结构的l_type 值必须是F_RDLCK、F_WRLCK或F_UNLCK。如果无法建立锁定,则返回-1,错误代码为EACCES 或EAGAIN。
F_SETLKW F_SETLK 作用相同,但是无法建立锁定时,此调用会一直等到锁定动作成功为止。若在等待锁定的过程中被信号中断时,会立即返回-1,错误代码为EINTR。
参数lock指针
参数lock指针为flock 结构指针,定义如下
struct flock
{
short int l_type;
short int l_whence;
off_t l_start;
off_t l_len;
pid_t l_pid;
};
l_type 有三种状态:
F_RDLCK 建立一个供读取用的锁定
F_WRLCK 建立一个供写入用的锁定
F_UNLCK 删除之前建立的锁定
l_whence 也有三种方式:
SEEK_SET 以文件开头为锁定的起始位置。
SEEK_CUR 以目前文件读写位置为锁定的起始位置
SEEK_END 以文件结尾为锁定的起始位置。
l_start 表示相对l_whence位置的偏移量,两者一起确定锁定区域的开始位置。
l_len表示锁定区域的长度,如果为0表示从起点(由l_whence和 l_start决定的开始位置)开始直到最大可能偏移量为止。即不管在后面增加多少数据都在锁的范围内。
返回值 成功返回依赖于cmd的值,若有错误则返回-1,错误原因存于errno.
所以当我们讲监听socket与客户端建链socket的状态都修改为非阻塞态时,那么问题当迎刃而解:
fcntl(sock_descriptor, F_SETFL, 0)
在修改成非阻塞态后,还是遇到了一些问题:
1) send失败,对端已拆链
2) 阻塞函数设置时非阻塞状态时的EAGAIN错误
这时的处理实际就类似异常的捕获行为,讲上述错误进行特殊处理。
Server:
#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <memory.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/select.h>#include <sys/socket.h>#include <sys/fcntl.h>#include <netinet/in.h>#include <arpa/inet.h>#define SUCCESS 0#define SERVERPORT 8888#define SOCKMAXCONN 512#define BUFFERSIZE 128struct fd_node{ int fd; struct fd_node *next;};struct fd_node *free_list = NULL;struct fd_node *work_list = NULL;int init_node_list(){ struct fd_node *curr = NULL; struct fd_node *temp = NULL; free_list = (struct fd_node*)malloc(sizeof(struct fd_node)); free_list->fd = -1; free_list->next = NULL; work_list = (struct fd_node*)malloc(sizeof(struct fd_node)); work_list->fd = -1; work_list->next = NULL; for (int i=0; i<SOCKMAXCONN; i++) { temp = (struct fd_node*)malloc(sizeof(struct fd_node)); temp->fd = -1; temp->next = free_list; free_list = temp; } return SUCCESS;}int free_node_list(){ struct fd_node *curr = NULL; while (free_list) { curr = free_list; free_list = curr->next; free(curr); } while (work_list) { curr = work_list; work_list = curr->next; free(curr); } return SUCCESS;}int move_node_to_free(struct fd_node *curr){ if (work_list == curr) { work_list = curr->next; curr->next = free_list; free_list = curr; } else { struct fd_node *temp = work_list; while (temp->next != curr && temp->next != NULL) { temp = temp->next; } temp->next = curr->next; curr->next = free_list; free_list = curr; } return SUCCESS;}int move_node_to_work(){ struct fd_node *curr = free_list; free_list = curr->next; curr->next = work_list; work_list = curr; return SUCCESS;}int main(){ char buffer[BUFFERSIZE] = {0}; fd_set readfds; int client_conn = 0; struct sockaddr_in client_socket_addr; struct sockaddr_in server_socket_addr; socklen_t length = sizeof(client_socket_addr); server_socket_addr.sin_family = AF_INET; server_socket_addr.sin_port = htons(SERVERPORT); server_socket_addr.sin_addr.s_addr = htonl(INADDR_ANY); int server_socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); fcntl(server_socket_fd, F_SETFL, O_NONBLOCK); if (SUCCESS != bind(server_socket_fd, (struct sockaddr *)&server_socket_addr, sizeof(server_socket_addr))) { perror ("Bind Socket Failed: "); goto exit; } if(SUCCESS != listen(server_socket_fd, SOCKMAXCONN)) { perror ("Listen Socket Failed: "); goto exit; }#ifdef NOBLOCK init_node_list(); for (;;) { int max_fd = server_socket_fd; struct fd_node *curr = work_list; FD_ZERO (&readfds); FD_SET (server_socket_fd, &readfds); int i = 0; while (curr->next) { max_fd = server_socket_fd>curr->fd ? server_socket_fd : curr->fd; FD_SET (curr->fd, &readfds); curr = curr->next; ++i; } printf ("Monitor number is : %d \n", i); if (select(max_fd+1, &readfds, NULL, NULL, NULL)<0) { perror("Select Failed: "); usleep(10); continue; } if (FD_ISSET(server_socket_fd, &readfds) && NULL != free_list->next) { FD_CLR(server_socket_fd, &readfds); free_list->fd = accept(server_socket_fd, (struct sockaddr*)&client_socket_addr, &length); fcntl(free_list->fd, F_SETFL, O_NONBLOCK); move_node_to_work(); if (free_list->next == NULL) { printf("Reach MAX FD number. \n"); } } curr = work_list; while (curr->next) { if (FD_ISSET(curr->fd, &readfds)) { memset(buffer, 0, sizeof(buffer)); int client_len = recv(curr->fd, buffer, BUFFERSIZE, 0); if (EAGAIN != errno && -1 == client_len) { perror ("Recv Socket Failed: "); continue; } if (0 == strncmp(buffer, "BYE", 4)) { move_node_to_free(curr); FD_CLR(curr->fd, &readfds); close(curr->fd); continue; } if (-1 == send(curr->fd, buffer, BUFFERSIZE, 0)) { if (EPIPE == errno || ECONNRESET == errno) { move_node_to_free(curr); FD_CLR(curr->fd, &readfds); close(curr->fd); } else { perror ("Send Socket Failed: "); } } } curr = curr->next; } } free_node_list();#else for (;;) { client_conn = accept(server_socket_fd, (struct sockaddr*)&client_socket_addr, &length); if (-1 == client_conn) { perror ("Connect Socket Failed: "); goto exit; } int client_len = recv(client_conn, buffer, sizeof(buffer), 0); if (-1 == client_len) { perror ("Recv Socket Failed: "); goto exit; } if (-1 == send(client_conn, buffer, client_len, 0)) { perror ("Send Socket Failed: "); goto exit; } printf("Received Request: %s !\n", buffer); close(client_conn); }#endif goto exit;exit: close(client_conn); close(server_socket_fd); return SUCCESS; }
Client:
#include <stdio.h>#include <stdlib.h>#include <memory.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#define SUCCESS 0#define SERVERPORT 8888int main(){ int fork_times = 0; int random_times = 9; char buffer[128] = {0}; struct sockaddr_in server_socket_addr = {0}; socklen_t server_addr_length = sizeof(server_socket_addr); server_socket_addr.sin_family = AF_INET; server_socket_addr.sin_port = htons(SERVERPORT); if( inet_pton(AF_INET, "127.0.0.1", &server_socket_addr.sin_addr) <= 0) { perror ("Inet_pton Socket Failed: "); goto exit; } do{ pid_t process = fork(); if (0 == process) { random_times = getpid()%5; break; } else { //printf ("%d create process %d \n", getpid(), process); usleep(10); } } while (++fork_times < 1024); int client_socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(SUCCESS != connect (client_socket_fd, (struct sockaddr*)&server_socket_addr, server_addr_length)) { perror ("Connect Socket Failed: "); goto exit; } for (int i=0; i<random_times; i++) { memset(buffer, 0, sizeof(buffer)); if (-1 == send(client_socket_fd, "Hello World!", 13, 0)) { perror ("Send Socket Failed: "); goto exit; } int client_len = recv(client_socket_fd, buffer, sizeof(buffer), 0); if (-1 == client_len) { perror ("Recv Socket Failed: "); goto exit; } //printf("[%4d:%4d] Received Response: %s !\n", getpid(), i, buffer); sleep(random_times%3); } send(client_socket_fd, "BYE", strlen("BYE"), 0); goto exit;exit: close(client_socket_fd); return SUCCESS; }
- socket 编程基础(三)
- Socket 基础编程(三)
- Socket的基础编程(三)
- EmeraldDB网络编程-socket编程基础(三)
- socket编程(三)
- socket编程(三)
- socket编程(三)
- 服务器开发【三】----网络编程的基础SOCKET(3)
- C# WinForm基础三 socket网络编程
- socket通信基础(三)
- Java基础 三步学会Java Socket编程(三)
- Java Socket编程(三)
- Java Socket编程(三)
- Java socket编程(三)
- Java(三) Socket编程
- linux socket 编程(三)
- socket编程入门(三)
- Java Socket编程(二)Socket基础
- Map线程安全几种实现方法
- systemd 常用指令和配置实例
- Java字符串
- 六大设计原则(上)
- iic总线
- Socket 基础编程(三)
- JAVA的StringBuffer类
- HTML中如何为表格添加标题(添加的标题与表格相对静止)(<table><caption>标题</caption></table>)
- Android的IPC机制(进程间通信)
- 基于MCP2515的Linux CAN总线驱动程序设计(二)
- L2-006. 树的遍历
- UVA/8-1 120
- MyEclipse安装插件的几种方法
- 20170307 只要吃东西咬坏了嘴唇,就停不下来