阻塞:
以读阻塞为例,如果缓冲区中有内容,则程序正常执行,
如果缓冲区没有内容,程序会一直阻塞,直到有内容,读取内容继续向下运行。
非阻塞:
以读阻塞为例,如果缓冲区中有内容,则程序正常执行,
如果缓冲区没有内容,程序会立即返回,然后继续向下运行。
超时检测:
介于阻塞和非阻塞之间,需要设置一定的时间,如果时间到达之前,缓冲区中没有数据
程序会阻塞,如果时间到了,缓冲区中还没有数据,则程序立即返回,继续向下执行。
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #define N 128
-
- #define ERRLOG(msg) do{\
- printf("%s,%s,[%d]\n", __FILE__, __func__, __LINE__);\
- perror(msg);\
- exit(-1);\
- }while(0)
-
- int main(int argc, char const *argv[])
- {
- if (argc != 3){
- ERRLOG("输入参数错误\n");
- }
-
- int socketfd;
- if (-1 == (socketfd = socket(AF_INET, SOCK_STREAM, 0))){
- ERRLOG("socket fd error");
- }
-
- struct sockaddr_in clientaddr;
- clientaddr.sin_family = AF_INET;
- clientaddr.sin_addr.s_addr = inet_addr(argv[1]);
- clientaddr.sin_port = htons(atoi(argv[2]));
- socklen_t clientaddr_len = sizeof(clientaddr);
-
- if (-1 == connect(socketfd,(struct sockaddr*)&clientaddr, clientaddr_len)){
- ERRLOG("connect error");
- }
-
- printf("连接成功...\n");
-
- char buff[N];
- while (1){
- memset(buff, 0, sizeof(buff));
-
- printf("请输入>>");
- fgets(buff, N, stdin);
- buff[strlen(buff) -1] = '\0';
-
- if (-1 == send(socketfd, buff, strlen(buff), 0)){
- ERRLOG("send error");
- }
-
- if (strncmp("quit", buff, 5) == 0){
- break;
- }
- memset(buff, 0, sizeof(buff));
- if (-1 == recv(socketfd, buff, sizeof(buff), 0)){
- ERRLOG("recv error");
- }
-
- printf("%s\n", buff);
- }
-
- close(socketfd);
- return 0;
- }
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #define N 128
-
- #define ERRLOG(msg) do{\
- printf("%s,%s,[%d]\n", __FILE__, __func__, __LINE__);\
- perror(msg);\
- exit(-1);\
- }while(0)
-
- int main(int argc, char const *argv[])
- {
- if (argc != 3){
- printf("输入格式错误\n");
- exit(-1);
- }
-
- int socketfd;
-
- if (-1 == (socketfd = socket(AF_INET, SOCK_STREAM, 0))){
- ERRLOG("socketfd erro");
- }
-
- struct sockaddr_in serveraddr;
- memset(&serveraddr, 0, sizeof(serveraddr));
- serveraddr.sin_family = AF_INET;
- serveraddr.sin_port = htons(atoi(argv[2]));
- serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
- socklen_t serveraddr_len = sizeof(serveraddr);
-
- if (-1 == bind(socketfd, (struct sockaddr*)&serveraddr, serveraddr_len)){
- ERRLOG("bind error");
- }
-
- if (-1 == listen(socketfd, 5)){
- ERRLOG("listen error");
- }
-
- int nbytes;
- int ret;
- int i;
- int maxfd = 0;
- int acceptfd;
- char buff[128] = {0};
-
- fd_set readfs;
- fd_set readfs_temp;
- FD_ZERO(&readfs);
- FD_ZERO(&readfs_temp);
-
- FD_SET(socketfd, &readfs);
- maxfd = maxfd > socketfd ? maxfd: socketfd;
-
- struct timeval tm;
- while (1){
- readfs_temp = readfs;
- tm.tv_sec = 5;
- tm.tv_usec = 0;
- if (-1 == (ret = select(maxfd + 1, &readfs_temp, NULL, NULL, &tm))){
- ERRLOG("select error");
- } else if (ret == 0){
- printf("timeout.....\n");
- } else {
- for (i = 3; i < maxfd + 1 && ret != 0; i++){
- if (FD_ISSET(i, &readfs_temp)){
- if (i == socketfd){
- if (-1 == (acceptfd = accept(i, NULL, NULL))){
- ERRLOG("acceptfd error");
- }
- printf("111111111\n");
- FD_SET(acceptfd, &readfs);
-
- maxfd = maxfd > acceptfd ? maxfd : acceptfd;
- } else {
- memset(buff, 0, sizeof(buff));
-
- if (-1 == (nbytes = recv(i, buff, sizeof(buff), 0))){
- ERRLOG("recv error");
- } else if(nbytes == 0){
- printf("断开链接...\n");
- FD_CLR(i, &readfs);
- close(i);
- continue;
- }
-
- if (!strncmp("quit", buff, 5)){
- printf("退出链接...\n");
- FD_CLR(i, &readfs);
- close(i);
- continue;
- }
-
- printf("%s\n", buff);
-
- strcat(buff, "hhhh");
-
- if (-1 == send(i, buff, sizeof(buff), 0)){
- ERRLOG("send error");
- }
- }
- ret--;
- }
- }
- }
- }
- close(socketfd);
- return 0;
- }
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- #define ERRLOG(msg) do{\
- printf("%s %s(%d):", __FILE__, __func__, __LINE__);\
- perror(msg);\
- exit(-1);\
- }while(0)
-
- #define N 128
-
-
- int main(int argc, char const *argv[])
- {
- if (argc != 3){
- printf("输入过程\n");
- exit(-1);
- }
-
- int socketfd;
- if (-1 == (socketfd = socket(AF_INET, SOCK_STREAM, 0))){
- ERRLOG("socket error");
- }
-
- struct sockaddr_in serveraddr;
- memset(&serveraddr, 0, sizeof(serveraddr));
- serveraddr.sin_family = AF_INET;
- serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
- serveraddr.sin_port = htons(atoi(argv[2]));
- socklen_t serveraddr_len = sizeof(serveraddr);
-
- if (-1 == bind(socketfd, (struct sockaddr*)&serveraddr, serveraddr_len)){
- ERRLOG("bind error");
- }
-
- if (-1 == listen(socketfd, 5)){
- ERRLOG("listen error");
- }
-
- int maxfd = 0;
- int ret = 0;
- int nbytes = 0;
- int i;
- int j;
- int acceptfd;
- char buff[128];
-
- struct pollfd my_fds[1024];
- for (i = 0; i < 1024; i++){
- my_fds[i].fd = -1;
- }
-
- my_fds[0].fd = socketfd;
- my_fds[0].events |= POLLIN;
- maxfd = maxfd > socketfd ? maxfd : socketfd;
-
- while (1){
- if (-1 == (ret = poll(my_fds, maxfd, 5000))){
-
- } else if (ret == 0){
- printf("time out...\n");
- } else {
- for (i = 0; i <= maxfd && ret != 0; i++){
- if (my_fds[i].revents & POLLIN != 0){
- if (my_fds[i].fd == socketfd){
- if (-1 == (acceptfd = accept(socketfd, NULL, NULL))){
- ERRLOG("accepfd error");
- }
-
- printf("客户端[%d]连接了\n", acceptfd);
-
- maxfd = maxfd > acceptfd ? maxfd : acceptfd;
-
- for (j = 0; j < 1024 ; j++){
- if (my_fds[j].fd == -1){
- my_fds[j].fd = acceptfd;
- my_fds[j].events = POLLIN;
-
- break;
- }
- }
-
- if (j == 1024){
- printf("满了\n");
- close(acceptfd);
- }
- }else {
- memset(buff, 0, sizeof(buff));
-
- if (-1 == (nbytes = recv(my_fds[i].fd, buff, 128, 0))){
- ERRLOG("recv error");
- }else if (nbytes == 0){
- printf("断开连接...\n");
- close(my_fds[i].fd);
- my_fds[i].fd = -1;
- continue;
- }
-
- if (!strncmp("quit", buff, 5)){
- printf("退出连接..\n");
- printf("断开连接...\n");
- close(my_fds[i].fd);
- my_fds[i].fd = -1;
- continue;
- }
-
- printf("%s\n", buff);
-
- strcat(buff, "jhhh");
-
- if (-1 == send(my_fds[i].fd, buff, sizeof(buff), 0)){
- ERRLOG("send errro");
- }
- }
- }
- }
- }
- }
-
-
- close(socketfd);
- return 0;
- }
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- #define ERRLOG(msg) do{\
- printf("%s %s(%d):", __FILE__, __func__, __LINE__);\
- perror(msg);\
- exit(-1);\
- }while(0)
-
- #define N 128
-
- typedef struct _MSG{
- int acceptfd;
- struct sockaddr_in clientaddr;
- }msg_t;
-
- void *deal_read_write(void *arg){
- msg_t msg = *(msg_t *)arg;
- char buff[N] = {0};
- int nbytes = 0;
- printf("客户端 [%s:%d] 连接了\n", inet_ntoa(msg.clientaddr.sin_addr), ntohs(msg.clientaddr.sin_port));
-
- //收发数据
- while(1){
- memset(buff, 0, N);
- //接受数据
- //由已经设置过超时时间的sockfd产生的accpetfd会继承超时属性
- //如果想设置的超时时间是一样的,直接使用即可
- //如果不想设置一样,也可以对每个acceptfd单独调用 setsockopt 进行设置
- if(-1 == (nbytes = recv(msg.acceptfd, buff, 128, 0))){
- if(errno == EAGAIN){
- printf("recv timeout..\n");
- close(msg.acceptfd);
- break;
- }
- perror("recv error");
- break;
- }else if(0 == nbytes){
- printf("[%s:%d]:断开了连接...\n", inet_ntoa(msg.clientaddr.sin_addr), ntohs(msg.clientaddr.sin_port));
- break;
- }
- if(!strncmp(buff, "quit", 5)){
- printf("[%s:%d]:退出了...\n", inet_ntoa(msg.clientaddr.sin_addr), ntohs(msg.clientaddr.sin_port));
- break;
- }
- //打印数据
- printf("[%s:%d]:[%s]\n", inet_ntoa(msg.clientaddr.sin_addr), ntohs(msg.clientaddr.sin_port), buff);
- //组装应答
- strcat(buff, "--hqyj");
- //发送应答
- if(-1 == send(msg.acceptfd, buff, N, 0)){
- ERRLOG("send error");
- }
- }
- close(msg.acceptfd);
- pthread_exit(NULL);
- }
-
- int main(int argc, const char *argv[]){
- if(3 != argc){
- printf("Usage: %s
\n" , argv[0]); - return -1;
- }
-
- //创建流式套接字
- int sockfd = socket(AF_INET, SOCK_STREAM, 0);
- if(-1 == sockfd){
- ERRLOG("socket error");
- }
-
- //填充服务器网络信息结构体
- struct sockaddr_in serveraddr;
- memset(&serveraddr, 0, sizeof(serveraddr));
- serveraddr.sin_family = AF_INET;
- //网络字节序的端口号 8888 9999 6789 等 都可以
- serveraddr.sin_port = htons(atoi(argv[2]));
- //网络字节序的IP地址,IP地址不能乱填
- //自己的主机ifconfig 查到的ip地址是多少就填多少
- //如果本机测试使用 也可以填写 127.0.0.1
- serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
-
- socklen_t serveraddr_len = sizeof(serveraddr);
-
- //设置允许端口复用
- int on = 1;
- if(-1 == setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))){
- perror("setsockopt error");
- }
-
- //将套接字和网络信息结构体绑定
- if(-1 == bind(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){
- ERRLOG("bind error");
- }
-
- //将套接字设置成被动监听状态
- if(-1 == listen(sockfd, 5)){
- ERRLOG("listen error");
- }
-
- //设置sockfd接收超时时间为 5s
- struct timeval tm;
- tm.tv_sec = 5;
- tm.tv_usec = 0;
- if(-1 == setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tm, sizeof(tm))){
- ERRLOG("setsockopt error");
- }
-
- //定义一个保存客户端信息的结构体
- struct sockaddr_in clientaddr;
- memset(&clientaddr, 0, sizeof(clientaddr));
- socklen_t clientaddr_len = sizeof(clientaddr);
-
- msg_t msg;
- pthread_t tid = 0;
-
- //阻塞等待客户端连接
- int acceptfd = 0;
- while(1){
- if(-1 == (acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &clientaddr_len))){
- if(errno == EAGAIN){
- printf("5秒内没有客户端连接到服务器..\n");
- continue;
- }
- ERRLOG("acceptfd error");
- }
- memset(&msg, 0, sizeof(msg));
- msg.clientaddr = clientaddr;
- msg.acceptfd = acceptfd;
- //有客户端连接就创建线程专门处理读写
- if(0 != pthread_create(&tid, NULL, deal_read_write, (void *)&msg)){
- ERRLOG("pthread_create error");
- }
-
- //设置线程分离属性 由操作系统回收线程的资源
- pthread_detach(tid);
- }
-
- close(sockfd);
-
- return 0;
- }
alarm是一个函数,可以通过他设置一个时间,当时间到达的时候,会给进程发一个
SIGALRM 信号。
使用alarm函数设置完超时时间后,进程会继续执行,直到设置的时间到了,
进程收到 SIGALRM 信号
进程对该信号默认的处理方式是 终止进程,我们的是服务器程序,不能使用默认的方式
所以需要对 该信号进行一个捕捉的操作。
如果使用 捕捉的操作,当信号产生时,回去执行信号处理函数,执行完信号处理函数
进程会继续向下执行,这种属性,叫做信号的自重启属性。
我们想要使用该信号实现超时检测,也就是说,执行完信号处理函数,不应该直接向下运行
而是应该给我们返回一个错误,也就是说,需要关闭信号的自重启属性。
- struct sigaction action;
- //获取旧的行为
- sigaction(SIGALRM, NULL, &action);
- //取消自重启属性
- action.sa_flags &= (~SA_RESTART);
- //指定信号处理函数
- action.sa_handler = my_function;
- //再将行为重新设置回去
- sigaction(SIGALRM, &action, NULL);
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- #define ERRLOG(msg) do{\
- printf("%s %s(%d):", __FILE__, __func__, __LINE__);\
- perror(msg);\
- exit(-1);\
- }while(0)
-
- #define N 128
-
- void my_function(int x){
- //什么都不用作 我们只是通过这种方法捕获信号
- printf("helle\n");
- }
-
- int main(int argc, const char *argv[]){
- if(3 != argc){
- printf("Usage: %s
\n" , argv[0]); - return -1;
- }
-
- //创建流式套接字
- int sockfd = socket(AF_INET, SOCK_STREAM, 0);
- if(-1 == sockfd){
- ERRLOG("socket error");
- }
-
- //填充服务器网络信息结构体
- struct sockaddr_in serveraddr;
- memset(&serveraddr, 0, sizeof(serveraddr));
- serveraddr.sin_family = AF_INET;
- //网络字节序的端口号 8888 9999 6789 等 都可以
- serveraddr.sin_port = htons(atoi(argv[2]));
- //网络字节序的IP地址,IP地址不能乱填
- //自己的主机ifconfig 查到的ip地址是多少就填多少
- //如果本机测试使用 也可以填写 127.0.0.1
- serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
-
- socklen_t serveraddr_len = sizeof(serveraddr);
-
- //设置端口复用
- int on = 1;
- if(-1 == setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))){
- perror("setsockopt error");
- }
-
- //将套接字和网络信息结构体绑定
- if(-1 == bind(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){
- ERRLOG("bind error");
- }
-
- //将套接字设置成被动监听状态
- if(-1 == listen(sockfd, 5)){
- ERRLOG("listen error");
- }
-
- //定义一个保存客户端信息的结构体
- struct sockaddr_in clientaddr;
- memset(&clientaddr, 0, sizeof(clientaddr));
- socklen_t clientaddr_len = sizeof(clientaddr);
-
- char buff[N] = {0};
- int nbytes = 0;
-
- //关闭SIGALRM信号的自重启属性
- struct sigaction action;
- //获取旧的行为
- sigaction(SIGALRM, NULL, &action);
- //取消自重启属性
- action.sa_flags &= (~SA_RESTART);
- //指定信号处理函数
- action.sa_handler = my_function;
- //再将行为重新设置回去
- sigaction(SIGALRM, &action, NULL);
-
- //阻塞等待客户端连接
- int acceptfd = 0;
- while(1){
- alarm(5);
- if(-1 == (acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &clientaddr_len))){
- if(errno == EINTR){
- printf("accept timeout..\n");
- continue;
- }
- ERRLOG("acceptfd error");
- }
- printf("客户端 [%s:%d] 连接了\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
-
- //收发数据
- while(1){
- memset(buff, 0, N);
- //接受数据
- alarm(5);
- if(-1 == (nbytes = recv(acceptfd, buff, 128, 0))){
- if(errno == EINTR){
- printf("recv timeout..\n");
- break;
- }
- ERRLOG("recv error");
- }else if(0 == nbytes){
- printf("[%s:%d]:断开了连接...\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
- break;
- }
- if(!strncmp(buff, "quit", 5)){
- printf("[%s:%d]:退出了...\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
- break;
- }
- //打印数据
- printf("[%s:%d]:[%s]\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port), buff);
- //组装应答
- strcat(buff, "--hqyj");
- //发送应答
- if(-1 == send(acceptfd, buff, N, 0)){
- ERRLOG("send error");
- }
- }
- //关闭套接字
- close(acceptfd);
- }
-
- //这句代码一般不会执行到
- //服务器程序一般不会主动退出
- close(sockfd);
-
- return 0;
- }