可正常工作的tcp服务器:

#include <netdb.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <signal.h>
#include <time.h>//测试方法,运行程序,并指定端口号8888
//在另一个终端上使用
// telnet 127.0.0.1 8888进行连接
//127.0.0.1是没有连接网络时使用的本地回环ip地址//使用浏览器测试,需要使用使用http协议进行,在浏览器中输入http://IP.8888 即可访问(本机测试)/*声明自定义函数*/
void sig_handler(int signo);
void out_addr(struct sockaddr_in *clientaddr);
void do_service(int fd);
int sockfd;int main(int argc, char * argv[])
{if(argc < 2){printf("usage: %s #port\n",argv[0]);exit(1);}if(signal(SIGINT, sig_handler) == SIG_ERR)   //开始捕捉信号  SIGINT{perror("signal sigint error!");exit(1);}/*步骤1创建socket*AF_INET IPV4*SOCK_STREAM 采用tcp协议*0 采用上面设置的协议类型*/sockfd = socket(AF_INET, SOCK_STREAM, 0);  //使用默认协议if(sockfd < 0){perror("socket error!");exit(1);}/**步骤2,:调用bind函数将socket和地址(包括 IP,port)进行绑定**/struct sockaddr_in serveraddr;  //声明专用地址,需要的时候再转换为通用地址memset(&serveraddr, 0, sizeof(serveraddr));//往地址填入ip、port、intnernet地址族类型serveraddr.sin_family = AF_INET; //IPV4serveraddr.sin_port = htons(atoi(argv[1]));  //填入端口 serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);if(bind(sockfd, (struct sockaddr *) &serveraddr,sizeof(serveraddr)) < 0){perror("bind error!");exit(1);}/* *步骤3:调用listen函数启动端口监听*通知系统去接受来自客户端的连接请求*listen 的第二个参数10是请求队列长度,将接收到的客户端连接请求放到对应的队列当中*/if(listen(sockfd, 10) < 0)  //10监听的队列的上限{perror("listen error!");exit(1);}/**步骤4:调用accept函数,从队列中获得*      一个客户端请求连接,并返回新的sock文件描述符fd,*      因为listen能够监听好多的连接请求,*      使用accept获得一个连接使用*      若是accept没有获得客户端连接,会进行阻塞,直到获得客户端连接*/struct sockaddr_in clientaddr;socklen_t clientaddr_len = sizeof(clientaddr);while(1){//使用循环就能够在断开与一个客户端连接之后,在连接下一个客户端连接int fd = accept(sockfd, (struct sockaddr*) &clientaddr,&clientaddr_len);if(fd < 0){perror("accept error!");continue;}/**步骤5: 调用IO函数(read/write)和连接的客户端进行双向通信**/out_addr(&clientaddr);do_service(fd);/*步骤6:关闭socket*/close(fd);}return 0;
}void sig_handler(int signo)
{if(signo == SIGINT){printf("server close\n");/*步骤6:关闭socket*/close(sockfd);exit(1);}}void out_addr(struct sockaddr_in *clientaddr)
{/*将端口网络字节序转换为主机字节序 */   /*port是short类型数据*/int port = ntohs(clientaddr->sin_port);char ip[16];memset(ip, 0, sizeof(ip));/*将ip地址从网络地址转换为点分十进制*//*需要注意的地方#include <arpa/inet.h>const char *inet_ntop(int af, const void *src,char *dst, socklen_t size);在函数中 const void *src说明第二个参数是指针类型的数据,但是当传入clientaddr->sin_addr.s_addr == (*clientaddr).sin_addr.s_addr就不在是一个指针类型数据因此需要使用&将其取址之后在传入。*/inet_ntop(AF_INET, &clientaddr->sin_addr.s_addr, ip, sizeof(ip));printf("client: %s(%d) connected\n",ip, port);
}void do_service(int fd)
{//获取系统时间long t = time(0);char *s = ctime(&t);size_t size = strlen(s)*sizeof(char);/*将服务器端获取的系统时间写回到客户端*/if(write(fd, s, size) != size){perror("write error!");}}

能正常工作的tcp客户端:

#include <netdb.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <signal.h>
#include <time.h>int main(int argc, char * argv[])
{if(argc < 3){printf("usage:%s ip port\n",argv[0]);exit(1);}/*步骤1:创建socket*/int sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd < 0){perror("socket error!");exit(1);}/*往serveraddr中填入ip,port和地址族类型(ipv4)*/struct sockaddr_in serveraddr;memset(&serveraddr, 0, sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(atoi(argv[2]));/*将字符串ip地址转换为网络字节序填入 serveraddr中*/inet_pton(AF_INET, argv[1], &serveraddr.sin_addr.s_addr);/**步骤2: 客户端调用connect函数连接到服务器端*/if(connect(sockfd, (struct sockaddr *)&serveraddr,sizeof(serveraddr)) < 0){perror("connect error!");exit(1);}/*步骤3:调用IO函数,read和write和服务器进行双向通信*/char buffer[1024];memset(buffer, 0, sizeof(buffer));size_t size;if((size = read(sockfd, buffer, sizeof(buffer))) < 0){perror("read error!");exit(1);}if(write(STDOUT_FILENO, buffer, size) != size){perror("write error!");exit(1);}/*步骤4:关闭socket套接字*/close(sockfd);return 0;
}

在do_service增加read之后,但是没有在客户端增加,发送数据函数,会造成阻塞,如:

void do_service(int fd)
{size_t len;char buff[20];if((len = read(fd, buff, 20)) < 0){perror("read error!");}//获取系统时间long t = time(0);char *s = ctime(&t);size_t size = strlen(s)*sizeof(char);/*将服务器端获取的系统时间写回到客户端*/if(write(fd, s, size) != size){perror("write error!");}}

更改之后的服务器:

#include <netdb.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <signal.h>
#include <time.h>//测试方法,运行程序,并指定端口号8888
//在另一个终端上使用
// telnet 127.0.0.1 8888进行连接
//127.0.0.1是没有连接网络时使用的本地回环ip地址//使用浏览器测试,需要使用使用http协议进行,在浏览器中输入http://IP.8888 即可访问(本机测试)/*声明自定义函数*/
void sig_handler(int signo);
void out_addr(struct sockaddr_in *clientaddr);
void do_service(int fd);
int sockfd;int main(int argc, char * argv[])
{if(argc < 2){printf("usage: %s #port\n",argv[0]);exit(1);}if(signal(SIGINT, sig_handler) == SIG_ERR)   //开始捕捉信号  SIGINT{perror("signal sigint error!");exit(1);}/*步骤1创建socket*AF_INET IPV4*SOCK_STREAM 采用tcp协议*0 采用上面设置的协议类型*/sockfd = socket(AF_INET, SOCK_STREAM, 0);  //使用默认协议if(sockfd < 0){perror("socket error!");exit(1);}/**步骤2,:调用bind函数将socket和地址(包括 IP,port)进行绑定**/struct sockaddr_in serveraddr;  //声明专用地址,需要的时候再转换为通用地址memset(&serveraddr, 0, sizeof(serveraddr));//往地址填入ip、port、intnernet地址族类型serveraddr.sin_family = AF_INET; //IPV4serveraddr.sin_port = htons(atoi(argv[1]));  //填入端口 serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);if(bind(sockfd, (struct sockaddr *) &serveraddr,sizeof(serveraddr)) < 0){perror("bind error!");exit(1);}/* *步骤3:调用listen函数启动端口监听*通知系统去接受来自客户端的连接请求*listen 的第二个参数10是请求队列长度,将接收到的客户端连接请求放到对应的队列当中*/if(listen(sockfd, 10) < 0)  //10监听的队列的上限{perror("listen error!");exit(1);}/**步骤4:调用accept函数,从队列中获得*      一个客户端请求连接,并返回新的sock文件描述符fd,*      因为listen能够监听好多的连接请求,*      使用accept获得一个连接使用*      若是accept没有获得客户端连接,会进行阻塞,直到获得客户端连接*/struct sockaddr_in clientaddr;socklen_t clientaddr_len = sizeof(clientaddr);while(1){//使用循环就能够在断开与一个客户端连接之后,在连接下一个客户端连接int fd = accept(sockfd, (struct sockaddr*) &clientaddr,&clientaddr_len);if(fd < 0){perror("accept error!");continue;}/**步骤5: 调用IO函数(read/write)和连接的客户端进行双向通信**/out_addr(&clientaddr);do_service(fd);/*步骤6:关闭socket*/close(fd);}return 0;
}void sig_handler(int signo)
{if(signo == SIGINT){printf("server close\n");/*步骤6:关闭socket*/close(sockfd);exit(1);}}void out_addr(struct sockaddr_in *clientaddr)
{/*将端口网络字节序转换为主机字节序 */   /*port是short类型数据*/int port = ntohs(clientaddr->sin_port);char ip[16];memset(ip, 0, sizeof(ip));/*将ip地址从网络地址转换为点分十进制*//*需要注意的地方#include <arpa/inet.h>const char *inet_ntop(int af, const void *src,char *dst, socklen_t size);在函数中 const void *src说明第二个参数是指针类型的数据,但是当传入clientaddr->sin_addr.s_addr == (*clientaddr).sin_addr.s_addr就不在是一个指针类型数据因此需要使用&将其取址之后在传入。*/inet_ntop(AF_INET, &clientaddr->sin_addr.s_addr, ip, sizeof(ip));printf("client: %s(%d) connected\n",ip, port);
}void do_service(int fd)
{size_t len;char buff[20];if((len = read(fd, buff, 20)) < 0){perror("read error!");}//获取系统时间long t = time(0);char *s = ctime(&t);size_t size = strlen(s)*sizeof(char);/*将服务器端获取的系统时间写回到客户端*/if(write(fd, s, size) != size){perror("write error!");}}

客户端的程序保持不变,经过测试,服务器会阻塞到read函数的地方。

不恰当使用read会造成服务器阻塞相关推荐

  1. 大文件上传服务器:支持超大文件HTTP断点续传的实现办法

    点击上方蓝色"方志朋",选择"设为星标"回复"666"获取独家整理的学习资料! 来源:blog.csdn.net/ababab12345/a ...

  2. 【原创】分布式之缓存击穿 【原创】自己动手实现静态资源服务器 【原创】自己动手实现JDK动态代理...

    [原创]分布式之缓存击穿 什么是缓存击穿 在谈论缓存击穿之前,我们先来回忆下从缓存中加载数据的逻辑,如下图所示 因此,如果黑客每次故意查询一个在缓存内必然不存在的数据,导致每次请求都要去存储层去查询, ...

  3. java 多线程监听同一个端口_使用多线程在Java服务器中同时侦听两个端口

    我正在构建一个简单的Java服务器,该服务器使用两个ServerSocket实例同时在两个端口上同时侦听客户端请求.这是服务器的代码: import java.io.PrintWriter; impo ...

  4. 服务器事件刷新消息,Windows Server 2003 中的 DNS 事件消息 1616 到 6702

    更多信息 一般 DNS 事件消息 1616 MessageId=1616 Severity=Error SymbolicName=DNS_EVENT_TEXT_STRING_TOO_LONG DNS ...

  5. 网络服务器开发总结(转:http://my.oschina.net/u/181613/blog/596022)

    一.概述 经过多年网络服务器开发实战,于此总结实践体会.本文涉及到异步连接.异步域名解析.热更新.过载保护.网络模型与架构及协程等,但不会涉及accept4.epoll等基本知识点. 二.可写事件 相 ...

  6. 大文件上传服务器、支持超大文件HTTP断点续传实践总结

    点击关注公众号,实用技术文章及时了解 来源:blog.csdn.net/ababab12345/ article/details/80490621 最近由于笔者所在的研发集团产品需要,需要支持高性能的 ...

  7. 三方协议的服务器,电子口岸电子支付签定三方协议是怎么操作的

    咨询我 法律问答顾问 (1)消费者和商家达成购销协议并选择用电子支票支付. (2)消费者通过网络向商家发出电子支票,同时向银行发出付款通知单. (3)商家通过验证中心对消费者提供的电子支票进行验证,验 ...

  8. 即时消息服务器eChat

    昨天写的博客设计方式.选择,今天为他补充一个用户评论的方式–即时消息 eChat是一个即时通信系统.基于SignalR,编程实现了一个B/S架构建立的网络聊天工具 即时通讯是互联网时代的产物,至于他的 ...

  9. 即时消息服务器eChat 与 通信解决方案

    昨天写的博客设计方式.选择,今天为他补充一个用户评论的方式–即时消息 eChat是一个即时通信系统.基于SignalR,编程实现了一个B/S架构建立的网络聊天工具 即时通讯是互联网时代的产物,至于他的 ...

最新文章

  1. 中美科技成果转化比较分析
  2. python字典排序
  3. Java深拷贝与浅拷贝
  4. mySql中使用命令行建表基本操作
  5. JavaScript实现strongly Connected Components 强连通分量算法(附完整源码)
  6. SQL Server 默认跟踪报表
  7. php查询sql2008数据库操作系统,使用 PHP 进行查询 - Azure SQL Database SQL Managed Instance | Microsoft Docs...
  8. 金蝶Apusic应用服务器的数据源管理(转)
  9. 编写C语言代码,实现以下功能:输入平面上两个点P1(x1,y1)和P2(x2,y2)的坐标,以这两个点为左上角和右下角可以确定一个矩形,输出这个矩形的周长。要求平面上点的坐标和矩形都用结构体来表示。
  10. RROR in main Module not found: Error: Can‘t resolve ‘index.js‘
  11. 阿里云centos云服务器 - 网站搭建教程
  12. twemproxy源码分析之四:处理流程ji(内容属于转载。
  13. java计算一个日子距离_java计算两地距离(公里)
  14. fn键台式计算机在哪,fn键在哪里
  15. 电脑开关电源维修图解
  16. elasticSearch API
  17. 2021年中国示波器行业及细分产品数字示波器市场现状分析[图]
  18. 蒙特卡洛模拟与matlab,用MATLAB进行蒙特卡洛模拟?
  19. 【微机原理】数字电路器件—门 与门 或门 非门电路及实例
  20. java实现文件管理

热门文章

  1. Fully Convolutional Networks for semantic Segmentation(深度学习经典论文翻译)
  2. NYOJ 741 数学家ST
  3. activiti 图片
  4. 设计模式学习之代理模式学习(一)
  5. 又见斐波那契~矩阵快速幂入门题
  6. 2017年9月18日
  7. 转;VC++中Format函数详解
  8. Json格式转化为string格式
  9. Winform打砖块游戏制作step by step第5节---重构代码,利用继承多态
  10. EntityFramework4.5使用Expression类创建动态查询及动态查询导航属性