TCP 客户端和服务器端
转自:http://blog.csdn.net/itcastcpp/article/details/39047265
前面几篇中实现的client每次运行只能从命令行读取一个字符串发给服务器,再从服务器收回来,现在我们把它改成交互式的,不断从终端接受用户输入并和server交互。
- /* client.c */
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include <netinet/in.h>
- #include "wrap.h"
- #define MAXLINE 80
- #define SERV_PORT 8000
- int main(int argc, char *argv[])
- {
- structsockaddr_in servaddr;
- charbuf[MAXLINE];
- intsockfd, n;
- sockfd= Socket(AF_INET, SOCK_STREAM, 0);
- bzero(&servaddr,sizeof(servaddr));
- servaddr.sin_family= AF_INET;
- inet_pton(AF_INET,"127.0.0.1", &servaddr.sin_addr);
- servaddr.sin_port= htons(SERV_PORT);
- Connect(sockfd,(struct sockaddr *)&servaddr, sizeof(servaddr));
- while(fgets(buf, MAXLINE, stdin) != NULL) {
- Write(sockfd,buf, strlen(buf));
- n= Read(sockfd, buf, MAXLINE);
- if(n == 0)
- printf("theother side has been closed.\n");
- else
- Write(STDOUT_FILENO,buf, n);
- }
- Close(sockfd);
- return0;
- }
编译并运行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,使它可以多次处理同一客户端的请求。
- /* server.c */
- #include <stdio.h>
- #include <string.h>
- #include <netinet/in.h>
- #include "wrap.h"
- #define MAXLINE 80
- #define SERV_PORT 8000
- int main(void)
- {
- structsockaddr_in servaddr, cliaddr;
- socklen_tcliaddr_len;
- intlistenfd, connfd;
- charbuf[MAXLINE];
- charstr[INET_ADDRSTRLEN];
- inti, n;
- listenfd= Socket(AF_INET, SOCK_STREAM, 0);
- bzero(&servaddr,sizeof(servaddr));
- servaddr.sin_family= AF_INET;
- servaddr.sin_addr.s_addr= htonl(INADDR_ANY);
- servaddr.sin_port= htons(SERV_PORT);
- Bind(listenfd,(struct sockaddr *)&servaddr, sizeof(servaddr));
- Listen(listenfd,20);
- printf("Acceptingconnections ...\n");
- while(1) {
- cliaddr_len= sizeof(cliaddr);
- connfd= Accept(listenfd,
- (structsockaddr *)&cliaddr, &cliaddr_len);
- while(1) {
- n= Read(connfd, buf, MAXLINE);
- if(n == 0) {
- printf("theother side has been closed.\n");
- break;
- }
- printf("receivedfrom %s at PORT %d\n",
- inet_ntop(AF_INET,&cliaddr.sin_addr, str, sizeof(str)),
- ntohs(cliaddr.sin_port));
- for(i = 0; i < n; i++)
- buf[i]= toupper(buf[i]);
- Write(connfd,buf, n);
- }
- Close(connfd);
- }
- }
经过上面的修改后,客户端和服务器可以进行多次交互了。
前面几篇中实现的client每次运行只能从命令行读取一个字符串发给服务器,再从服务器收回来,现在我们把它改成交互式的,不断从终端接受用户输入并和server交互。
- /* client.c */
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include <netinet/in.h>
- #include "wrap.h"
- #define MAXLINE 80
- #define SERV_PORT 8000
- int main(int argc, char *argv[])
- {
- structsockaddr_in servaddr;
- charbuf[MAXLINE];
- intsockfd, n;
- sockfd= Socket(AF_INET, SOCK_STREAM, 0);
- bzero(&servaddr,sizeof(servaddr));
- servaddr.sin_family= AF_INET;
- inet_pton(AF_INET,"127.0.0.1", &servaddr.sin_addr);
- servaddr.sin_port= htons(SERV_PORT);
- Connect(sockfd,(struct sockaddr *)&servaddr, sizeof(servaddr));
- while(fgets(buf, MAXLINE, stdin) != NULL) {
- Write(sockfd,buf, strlen(buf));
- n= Read(sockfd, buf, MAXLINE);
- if(n == 0)
- printf("theother side has been closed.\n");
- else
- Write(STDOUT_FILENO,buf, n);
- }
- Close(sockfd);
- return0;
- }
编译并运行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,使它可以多次处理同一客户端的请求。
- /* server.c */
- #include <stdio.h>
- #include <string.h>
- #include <netinet/in.h>
- #include "wrap.h"
- #define MAXLINE 80
- #define SERV_PORT 8000
- int main(void)
- {
- structsockaddr_in servaddr, cliaddr;
- socklen_tcliaddr_len;
- intlistenfd, connfd;
- charbuf[MAXLINE];
- charstr[INET_ADDRSTRLEN];
- inti, n;
- listenfd= Socket(AF_INET, SOCK_STREAM, 0);
- bzero(&servaddr,sizeof(servaddr));
- servaddr.sin_family= AF_INET;
- servaddr.sin_addr.s_addr= htonl(INADDR_ANY);
- servaddr.sin_port= htons(SERV_PORT);
- Bind(listenfd,(struct sockaddr *)&servaddr, sizeof(servaddr));
- Listen(listenfd,20);
- printf("Acceptingconnections ...\n");
- while(1) {
- cliaddr_len= sizeof(cliaddr);
- connfd= Accept(listenfd,
- (structsockaddr *)&cliaddr, &cliaddr_len);
- while(1) {
- n= Read(connfd, buf, MAXLINE);
- if(n == 0) {
- printf("theother side has been closed.\n");
- break;
- }
- printf("receivedfrom %s at PORT %d\n",
- inet_ntop(AF_INET,&cliaddr.sin_addr, str, sizeof(str)),
- ntohs(cliaddr.sin_port));
- for(i = 0; i < n; i++)
- buf[i]= toupper(buf[i]);
- Write(connfd,buf, n);
- }
- Close(connfd);
- }
- }
经过上面的修改后,客户端和服务器可以进行多次交互了。
TCP 客户端和服务器端相关推荐
- Java实现简易TCP客户端、服务器端通信程序
本学期计算机网络课程要求完成一个TCP和一个UDP的通信程序,我完成了功能的简单实现,下面讲讲我的TCP程序的实现.(UDP的见另一篇博客) 目录 效果展示 一.项目结构 二.完整代码 1.TCPCl ...
- 用python和NetAssist来做TCP客户端和服务器端
轻松下载一个网络调试助手,用python实现TCP通信 目录 前言 一.TCP是什么? 1.TCP(Transmission Control Protocol)概念 2.TCP通信的简明三步骤 3.T ...
- 实验一 基于TCP和UDP的客户端和服务器端
基于TCP和UDP的客户端和服务器端 一. 实验要求 二.实验目的 三. 实验环境 四. 实验内容 五. 实验原代码 六. 实验结论 七. 实验错误及改正 八. 总结 一. 实验要求 (1)分别编写基 ...
- Socket之TCP客户端【Python】
下面是其他相关的终端的创建: Socket之TCP服务器[Python] Socket之UDP服务器[Python] Socket之UDP客户端[Python] 同样的,跟创建TCP服务器一样,我们也 ...
- Java刷题知识点之TCP、UDP、TCP和UDP的区别、socket、TCP编程的客户端一般步骤、TCP编程的服务器端一般步骤、UDP编程的客户端一般步骤、UDP编程的服务器端一般步骤...
TCP和UDP是两个传输层协议,广泛应用于网络中不同主机之间传输数据.对任何程序员来说,熟悉TCP和UDP的工作方式都是至关重要的.这就是为什么TCP和UDP是一个流行的Java编程面试问题. Jav ...
- JAVA学习-JAVA实现客户端与服务器端的TCP通信
JAVA实现客户端与服务器端的TCP通信 (JAVA 工程训练阶段一.训练任务三基本通信能力.基本任务3.2javaTCP 通信) 编写两个java application 应用程序,完成以下功能: ...
- TCP协议客户端与服务器端一般的通信过程
服务器初始化 (1)调用socket,创建文件描述符 (2)调用bind,将文件描述符与ip/port连接起来.若端口号已被占用,则bind失败 (3)调用listen,声明该文件描述符是服务器的一个 ...
- 网闸虚拟服务器,tcp客户端和tcp服务器端 网闸
tcp客户端和tcp服务器端 网闸 内容精选 换一换 负载均衡器是指您创建的承载业务的负载均衡服务实体.创建负载均衡器后,您还需要在负载均衡器中添加监听器和后端服务器,然后才能使用负载均衡服务提供的功 ...
- 墨麟科技Java服务器_基于TCP的客户端和服务器端的代码设计
实验平台 linux 实验内容 编写TCP服务器和客户端程序,程序运行时服务器等待客户端连接.一旦连接成功,服务器显示客户端的IP地址和端口号,并向客户端发送字符串 实验原理 TCP是面向连接的通信, ...
最新文章
- Internet History, Technology, and Security----第三周
- https://toonify.photos/ for Disney style
- [AGC016B]Colorful Hats
- Neo4j导入:java.lang.IllegalStateException:不支持在单个导入中混合指定和未指定的组所有物...
- Lync Server 2010所需媒体网络流量带宽详解和计算
- android sdk 封装html5,Android平台以WebView方式集成HTML5+SDK方法
- ReactJs 高级篇一 Context 使用
- 绒毛动物探测器:通过TensorFlow.js中的迁移学习识别浏览器中的自定义对象
- c#的FileSystemWatcher对象监视文件的变化的事件,无休止的触发事件的解决办法
- ssh1—xshell免密登录
- Windows系统快速查找文件
- Go函数和方法的区别
- ubuntu 局域网连接
- 使用中文维基百科语料库训练一个word2vec模型
- 贝叶斯统计学习笔记|Bayesian Statistics|Metropolis-Hastings与Gibbs Sampling
- 原来PID是在老王头和老斯基的斗争中诞生的
- 365天挑战LeetCode1000题——Day 124 单调队列模板
- rebound(反弹)攻击技术分析
- windows系统整机迁移 克隆到新电脑 原来的应用软件都还在 无需重新安装
- php答题闯关游戏,陌陌新上线“答题闯关”对战小游戏 涨知识得现金红包
热门文章
- 逻辑表达式——黑纸白纸
- ARC_xp_20160530
- Python服务器开发三:Socket
- CLI下的网页浏览器之二——Lynx
- 张向东:就以当年期望别人对我们那样的方式
- 中文简体字-繁体字转换 WEB 服务(源代码)
- 笔记本电脑怎么清理灰尘_手机声音越用越小怎么办?一段黑科技音波就能清理扬声器灰尘...
- 二元置信椭圆r语言_医学统计与R语言:圆形树状图(circular dendrogram)
- php关联数组和哈希表,php遍历哈希表及关联数组的实例代码
- php put 参数,php – 如何在Guzzle 5中发送PUT请求的参数?