转自:http://blog.csdn.net/itcastcpp/article/details/39047265

前面几篇中实现的client每次运行只能从命令行读取一个字符串发给服务器,再从服务器收回来,现在我们把它改成交互式的,不断从终端接受用户输入并和server交互。

[cpp] view plain copy
  1. /* client.c */
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <netinet/in.h>
  6. #include "wrap.h"
  7. #define MAXLINE 80
  8. #define SERV_PORT 8000
  9. int main(int argc, char *argv[])
  10. {
  11. structsockaddr_in servaddr;
  12. charbuf[MAXLINE];
  13. intsockfd, n;
  14. sockfd= Socket(AF_INET, SOCK_STREAM, 0);
  15. bzero(&servaddr,sizeof(servaddr));
  16. servaddr.sin_family= AF_INET;
  17. inet_pton(AF_INET,"127.0.0.1", &servaddr.sin_addr);
  18. servaddr.sin_port= htons(SERV_PORT);
  19. Connect(sockfd,(struct sockaddr *)&servaddr, sizeof(servaddr));
  20. while(fgets(buf, MAXLINE, stdin) != NULL) {
  21. Write(sockfd,buf, strlen(buf));
  22. n= Read(sockfd, buf, MAXLINE);
  23. if(n == 0)
  24. printf("theother side has been closed.\n");
  25. else
  26. Write(STDOUT_FILENO,buf, n);
  27. }
  28. Close(sockfd);
  29. return0;
  30. }

编译并运行server和client,看看是否达到了你预想的结果。

这时server仍在运行,但是client的运行结果并不正确。原因是什么呢?仔细查看server.c可以发现,server对每个请求只处理一次,应答后就关闭连接,client不能继续使用这个连接发送数据。但是client下次循环时又调用write发数据给server,write调用只负责把数据交给TCP发送缓冲区就可以成功返回了,所以不会出错,而server收到数据后应答一个RST段,client收到RST段后无法立刻通知应用层,只把这个状态保存在TCP协议层。client下次循环又调用write发数据给server,由于TCP协议层已经处于RST状态了,因此不会将数据发出,而是发一个SIGPIPE信号给应用层,SIGPIPE信号的缺省处理动作是终止程序,所以看到上面的现象。

为了避免client异常退出,上面的代码应该在判断对方关闭了连接后break出循环,而不是继续write。另外,有时候代码中需要连续多次调用write,可能还来不及调用read得知对方已关闭了连接就被SIGPIPE信号终止掉了,这就需要在初始化时调用sigaction处理SIGPIPE信号,如果SIGPIPE信号没有导致进程异常退出,write返回-1并且errno为EPIPE。

另外,我们需要修改server,使它可以多次处理同一客户端的请求。

[cpp] view plain copy
  1. /* server.c */
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <netinet/in.h>
  5. #include "wrap.h"
  6. #define MAXLINE 80
  7. #define SERV_PORT 8000
  8. int main(void)
  9. {
  10. structsockaddr_in servaddr, cliaddr;
  11. socklen_tcliaddr_len;
  12. intlistenfd, connfd;
  13. charbuf[MAXLINE];
  14. charstr[INET_ADDRSTRLEN];
  15. inti, n;
  16. listenfd= Socket(AF_INET, SOCK_STREAM, 0);
  17. bzero(&servaddr,sizeof(servaddr));
  18. servaddr.sin_family= AF_INET;
  19. servaddr.sin_addr.s_addr= htonl(INADDR_ANY);
  20. servaddr.sin_port= htons(SERV_PORT);
  21. Bind(listenfd,(struct sockaddr *)&servaddr, sizeof(servaddr));
  22. Listen(listenfd,20);
  23. printf("Acceptingconnections ...\n");
  24. while(1) {
  25. cliaddr_len= sizeof(cliaddr);
  26. connfd= Accept(listenfd,
  27. (structsockaddr *)&cliaddr, &cliaddr_len);
  28. while(1) {
  29. n= Read(connfd, buf, MAXLINE);
  30. if(n == 0) {
  31. printf("theother side has been closed.\n");
  32. break;
  33. }
  34. printf("receivedfrom %s at PORT %d\n",
  35. inet_ntop(AF_INET,&cliaddr.sin_addr, str, sizeof(str)),
  36. ntohs(cliaddr.sin_port));
  37. for(i = 0; i < n; i++)
  38. buf[i]= toupper(buf[i]);
  39. Write(connfd,buf, n);
  40. }
  41. Close(connfd);
  42. }
  43. }

经过上面的修改后,客户端和服务器可以进行多次交互了。

前面几篇中实现的client每次运行只能从命令行读取一个字符串发给服务器,再从服务器收回来,现在我们把它改成交互式的,不断从终端接受用户输入并和server交互。

[cpp] view plain copy
  1. /* client.c */
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <netinet/in.h>
  6. #include "wrap.h"
  7. #define MAXLINE 80
  8. #define SERV_PORT 8000
  9. int main(int argc, char *argv[])
  10. {
  11. structsockaddr_in servaddr;
  12. charbuf[MAXLINE];
  13. intsockfd, n;
  14. sockfd= Socket(AF_INET, SOCK_STREAM, 0);
  15. bzero(&servaddr,sizeof(servaddr));
  16. servaddr.sin_family= AF_INET;
  17. inet_pton(AF_INET,"127.0.0.1", &servaddr.sin_addr);
  18. servaddr.sin_port= htons(SERV_PORT);
  19. Connect(sockfd,(struct sockaddr *)&servaddr, sizeof(servaddr));
  20. while(fgets(buf, MAXLINE, stdin) != NULL) {
  21. Write(sockfd,buf, strlen(buf));
  22. n= Read(sockfd, buf, MAXLINE);
  23. if(n == 0)
  24. printf("theother side has been closed.\n");
  25. else
  26. Write(STDOUT_FILENO,buf, n);
  27. }
  28. Close(sockfd);
  29. return0;
  30. }

编译并运行server和client,看看是否达到了你预想的结果。

这时server仍在运行,但是client的运行结果并不正确。原因是什么呢?仔细查看server.c可以发现,server对每个请求只处理一次,应答后就关闭连接,client不能继续使用这个连接发送数据。但是client下次循环时又调用write发数据给server,write调用只负责把数据交给TCP发送缓冲区就可以成功返回了,所以不会出错,而server收到数据后应答一个RST段,client收到RST段后无法立刻通知应用层,只把这个状态保存在TCP协议层。client下次循环又调用write发数据给server,由于TCP协议层已经处于RST状态了,因此不会将数据发出,而是发一个SIGPIPE信号给应用层,SIGPIPE信号的缺省处理动作是终止程序,所以看到上面的现象。

为了避免client异常退出,上面的代码应该在判断对方关闭了连接后break出循环,而不是继续write。另外,有时候代码中需要连续多次调用write,可能还来不及调用read得知对方已关闭了连接就被SIGPIPE信号终止掉了,这就需要在初始化时调用sigaction处理SIGPIPE信号,如果SIGPIPE信号没有导致进程异常退出,write返回-1并且errno为EPIPE。

另外,我们需要修改server,使它可以多次处理同一客户端的请求。

[cpp] view plain copy
  1. /* server.c */
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <netinet/in.h>
  5. #include "wrap.h"
  6. #define MAXLINE 80
  7. #define SERV_PORT 8000
  8. int main(void)
  9. {
  10. structsockaddr_in servaddr, cliaddr;
  11. socklen_tcliaddr_len;
  12. intlistenfd, connfd;
  13. charbuf[MAXLINE];
  14. charstr[INET_ADDRSTRLEN];
  15. inti, n;
  16. listenfd= Socket(AF_INET, SOCK_STREAM, 0);
  17. bzero(&servaddr,sizeof(servaddr));
  18. servaddr.sin_family= AF_INET;
  19. servaddr.sin_addr.s_addr= htonl(INADDR_ANY);
  20. servaddr.sin_port= htons(SERV_PORT);
  21. Bind(listenfd,(struct sockaddr *)&servaddr, sizeof(servaddr));
  22. Listen(listenfd,20);
  23. printf("Acceptingconnections ...\n");
  24. while(1) {
  25. cliaddr_len= sizeof(cliaddr);
  26. connfd= Accept(listenfd,
  27. (structsockaddr *)&cliaddr, &cliaddr_len);
  28. while(1) {
  29. n= Read(connfd, buf, MAXLINE);
  30. if(n == 0) {
  31. printf("theother side has been closed.\n");
  32. break;
  33. }
  34. printf("receivedfrom %s at PORT %d\n",
  35. inet_ntop(AF_INET,&cliaddr.sin_addr, str, sizeof(str)),
  36. ntohs(cliaddr.sin_port));
  37. for(i = 0; i < n; i++)
  38. buf[i]= toupper(buf[i]);
  39. Write(connfd,buf, n);
  40. }
  41. Close(connfd);
  42. }
  43. }

经过上面的修改后,客户端和服务器可以进行多次交互了。

TCP 客户端和服务器端相关推荐

  1. Java实现简易TCP客户端、服务器端通信程序

    本学期计算机网络课程要求完成一个TCP和一个UDP的通信程序,我完成了功能的简单实现,下面讲讲我的TCP程序的实现.(UDP的见另一篇博客) 目录 效果展示 一.项目结构 二.完整代码 1.TCPCl ...

  2. 用python和NetAssist来做TCP客户端和服务器端

    轻松下载一个网络调试助手,用python实现TCP通信 目录 前言 一.TCP是什么? 1.TCP(Transmission Control Protocol)概念 2.TCP通信的简明三步骤 3.T ...

  3. 实验一 基于TCP和UDP的客户端和服务器端

    基于TCP和UDP的客户端和服务器端 一. 实验要求 二.实验目的 三. 实验环境 四. 实验内容 五. 实验原代码 六. 实验结论 七. 实验错误及改正 八. 总结 一. 实验要求 (1)分别编写基 ...

  4. Socket之TCP客户端【Python】

    下面是其他相关的终端的创建: Socket之TCP服务器[Python] Socket之UDP服务器[Python] Socket之UDP客户端[Python] 同样的,跟创建TCP服务器一样,我们也 ...

  5. Java刷题知识点之TCP、UDP、TCP和UDP的区别、socket、TCP编程的客户端一般步骤、TCP编程的服务器端一般步骤、UDP编程的客户端一般步骤、UDP编程的服务器端一般步骤...

    TCP和UDP是两个传输层协议,广泛应用于网络中不同主机之间传输数据.对任何程序员来说,熟悉TCP和UDP的工作方式都是至关重要的.这就是为什么TCP和UDP是一个流行的Java编程面试问题. Jav ...

  6. JAVA学习-JAVA实现客户端与服务器端的TCP通信

    JAVA实现客户端与服务器端的TCP通信 (JAVA 工程训练阶段一.训练任务三基本通信能力.基本任务3.2javaTCP 通信) 编写两个java application 应用程序,完成以下功能: ...

  7. TCP协议客户端与服务器端一般的通信过程

    服务器初始化 (1)调用socket,创建文件描述符 (2)调用bind,将文件描述符与ip/port连接起来.若端口号已被占用,则bind失败 (3)调用listen,声明该文件描述符是服务器的一个 ...

  8. 网闸虚拟服务器,tcp客户端和tcp服务器端 网闸

    tcp客户端和tcp服务器端 网闸 内容精选 换一换 负载均衡器是指您创建的承载业务的负载均衡服务实体.创建负载均衡器后,您还需要在负载均衡器中添加监听器和后端服务器,然后才能使用负载均衡服务提供的功 ...

  9. 墨麟科技Java服务器_基于TCP的客户端和服务器端的代码设计

    实验平台 linux 实验内容 编写TCP服务器和客户端程序,程序运行时服务器等待客户端连接.一旦连接成功,服务器显示客户端的IP地址和端口号,并向客户端发送字符串 实验原理 TCP是面向连接的通信, ...

最新文章

  1. Internet History, Technology, and Security----第三周
  2. https://toonify.photos/ for Disney style
  3. [AGC016B]Colorful Hats
  4. Neo4j导入:java.lang.IllegalStateException:不支持在单个导入中混合指定和未指定的组所有物...
  5. Lync Server 2010所需媒体网络流量带宽详解和计算
  6. android sdk 封装html5,Android平台以WebView方式集成HTML5+SDK方法
  7. ReactJs 高级篇一 Context 使用
  8. 绒毛动物探测器:通过TensorFlow.js中的迁移学习识别浏览器中的自定义对象
  9. c#的FileSystemWatcher对象监视文件的变化的事件,无休止的触发事件的解决办法
  10. ssh1—xshell免密登录
  11. Windows系统快速查找文件
  12. Go函数和方法的区别
  13. ubuntu 局域网连接
  14. 使用中文维基百科语料库训练一个word2vec模型
  15. 贝叶斯统计学习笔记|Bayesian Statistics|Metropolis-Hastings与Gibbs Sampling
  16. 原来PID是在老王头和老斯基的斗争中诞生的
  17. 365天挑战LeetCode1000题——Day 124 单调队列模板
  18. rebound(反弹)攻击技术分析
  19. windows系统整机迁移 克隆到新电脑 原来的应用软件都还在 无需重新安装
  20. php答题闯关游戏,陌陌新上线“答题闯关”对战小游戏 涨知识得现金红包

热门文章

  1. 逻辑表达式——黑纸白纸
  2. ARC_xp_20160530
  3. Python服务器开发三:Socket
  4. CLI下的网页浏览器之二——Lynx
  5. 张向东:就以当年期望别人对我们那样的方式
  6. 中文简体字-繁体字转换 WEB 服务(源代码)
  7. 笔记本电脑怎么清理灰尘_手机声音越用越小怎么办?一段黑科技音波就能清理扬声器灰尘...
  8. 二元置信椭圆r语言_医学统计与R语言:圆形树状图(circular dendrogram)
  9. php关联数组和哈希表,php遍历哈希表及关联数组的实例代码
  10. php put 参数,php – 如何在Guzzle 5中发送PUT请求的参数?