TCP客户/服务器程序实例

2023-11-03 09:08

本文主要是介绍TCP客户/服务器程序实例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转自:http://www.cnblogs.com/biyeymyhjob/archive/2012/08/05/2624007.html


1.概述

这章的TCP客户/服务器模型

2.TCP回射服务器程序

1).main函数

 

复制代码
#include      "unp.h"int main(int argc, char **argv)
{int     listenfd, connfd;pid_t   childpid;socklen_t clilen;struct sockaddr_in cliaddr, servaddr;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, (SA *) &servaddr, sizeof(servaddr));Listen(listenfd, LISTENQ);for ( ; ; )  {clilen = sizeof(cliaddr);connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);if ( (childpid = Fork()) == 0) {                  /* child process */Close(listenfd);                              /* close listening socket */str_echo(connfd);                             /* process the request */exit (0);}Close(connfd);                                    /* parent closes connected socket */}
}
复制代码

 

2).str_echo函数

复制代码
#include    "unp.h"void str_echo(int sockfd)
{ssize_t n;char    buf[MAXLINE];again:while ( (n = read(sockfd, buf, MAXLINE)) > 0)Writen(sockfd, buf, n);if (n < 0 && errno == EINTR)goto again;else if (n < 0)err_sys("str_echo: read error");
}
复制代码

 

 

 

3.TCP回射客户程序

1).main函数

复制代码
#include    "unp.h"int main(int argc, char **argv)
{int     sockfd;struct sockaddr_in servaddr;if (argc != 2)err_quit("usage: tcpcli <IPaddress>");sockfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SERV_PORT);Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));str_cli(stdin, sockfd);     /* do it all */exit(0);
}
复制代码

 

2).str_cli函数

复制代码
#include    "unp.h"void str_cli(FILE *fp, int sockfd)
{char    sendline[MAXLINE], recvline[MAXLINE];while (Fgets(sendline, MAXLINE, fp) != NULL) {Writen(sockfd, sendline, strlen (sendline));if (Readline(sockfd, recvline, MAXLINE) == 0)err_quit("str_cli: server terminated prematurely");Fputs(recvline, stdout);}
}
复制代码

 

 

 

4.POSIX 信号处理

每个信号都有一个处理办法(disposition),也称为与此信号关联的行为(action)。我们通过调用函数sigaction来设置一个信号的处理办法。
1).可以提供一个函数,在信号发生时随即调用。这个函数称为信号处理函数(signal handler),而此行为便称为捕获(catching)信号,有两个信号不能捕获SIGKILL和SIGSTOP,函数由信号值这一单一参数来调用且无返回值,函数原型为

void handler(int signo);

信号SIGIO,SIGPOLL,SIGURG还要求捕获它的进程有其它动作。

2).可以通过设置信号的处理办法为SIG_IGN来忽略它,但是SIGKILL和SIGSTOP不能忽略。

3).可以设置信号的处理办法为SIG_DFL来为它设置缺省处理办法

函数signal的函数原型层次复杂

void ( * signal (int signo, void ( * func)(int) ) )(int);

用typedef简化函数原型

typedef void Sigfunc(int); // 它说明信号处理程序是带有一个整形参数且无返回值的函数

这样signal的函数原型就变为

Sigfunc * signal (int signo, Sigfunc * func); // 此函数的第二个参数和返回值都是指向信号处理函数的指针

 

5.处理SIGCHLD信号

设置僵尸(Zombie)状态的目的就是维护子进程的信息,以便父进程在稍后的某个时候取回。如果一个进程终止,且该进程有子程序处于僵尸状态,则所有僵尸子进程的父进程ID均置为1(init进程),init进程将作为这些子进程的继父,并负责清除他们(也就是说,init进程将wait它们,从而去除僵尸进程),有些Unix系统给僵尸进程输出的COMMAND列为<defunct>(ps命令输出)。

另外:

  • 如果fork子进程,那么就要wait它们,以防止它们变成僵死进程。
  • 捕获SIGCHLD信号,并在信号处理函数中wait子进程,我们始终应该调用waitpid而非wait来处理子进程
  • 我们始终应该检查慢系统调用是否返回EINTR错误。并决定是否重启这些系统调用。(一些系统会自动重启被中断的系统调用)。
  • connect不能被重启,当connect函数被信号中断且不自动重启时,我们必须调用select来等待连接完成

 

 

 

6.wait和waitpid函数

可以调用如下两个函数处理已终止的子进程

#include <sys/wait.h>pid_t wait (int *statloc);pid_t waitpid (pid_t pid, int *statloc, int options);
//返回值:成功返回进程ID,出错返回返回0或-1;

对于参数pid 想等待的进程ID号。-1表示等待第一个结束的子进程,options附加选项,常用的是WNOHANG,告知内核在没有以终止子进程时不要阻塞

函数wait和waitpid均返回两个值: 函数的返回值是终止子进程的进程ID号,子进程的终止状态(一个整数)则是通过指针statloc返回的。

wait和waitpid的区别: wait 等待第一个结束的子进程,如果没有结束的子进程,wait将阻塞。waitpid 通过参数设置,可以在没有子进程结束时waitpid不阻塞

 

 

7.accept返回前连接终止

 Berkeley 的实现在内核中处理终止的连接。POSIX 规定返回一个ECONNABORTED 的 errno(详见UNP3)

 

 

8.服务进程终止

 如果向一个服务进程已终止的服务器发起连接,服务器将返回一个RST 信号

 PS RST:(Reset the connection)用于复位因某种原因引起出现的错误连接,也用来拒绝非法数据和请求

 

9.SIGPIPE信号

  • 当一个进程向某个已收到RST的套接字执行写操作时,内核向该进程发送一个SIGPIPE信号,
  • SIGPIPE信号的默认行为是终止进程

 

10.服务器主机崩溃

如果,客户端和服务器已经建立了连接的时候,此时服务器崩溃(达到这一标准可以把服务器的网线拔掉,这个时候,服务器就不能发送FIN数据报了,和关机不一样的)

  • 如果这时客户端向服务器发送数据的时候,因为服务器已经不存在了,那么客户端就不能接受到服务器给客户端的ack信息,这个时候,客户端建立的是TCP连接,就会重发数据报,而服务器对客户的数据分节根本没有响应,那么所返回的错误就是ETIMEDOUT。
  • 如果中间某个路由判断目的主机不可到达,从而响应一个"destination ETINEDOUT"(目的地不可达)ICMP消息,所返回的错误是EHOSTUNREACH或者ENETUNREACH

 

11.服务器主机崩溃后重启

当客户端和服务器已经建立连接的时候,服务器发生崩溃,重新启动的时候,丢失了原来和客户端的连接信息,这个时候,当客户端向服务器发送数据的时候(客户端并不知道,服务器已经忘记三次握手了),此时服务器发送RST数据报,就结束了客户端的发送

 

12.服务器主机关机

 Unix系统关机时,init进程通常先给所有进程发送SIGTERM信号。等待5-20秒后给所有仍然在运行的进程发送SIGKILL信号,这么做的目的是给进程一小段时间来清除和终止。

 

13.TCP程序例子小结

需要通信的客户/服务器程序在通信之前都要指定套接字对:本地IP地址,本地端口号,外地IP地址,外地端口。

客户程序的本地IP地址和本地端口号通常是内核分配。服务程序的本地IP地址和端口号有bind函数指定

 

14.数据格式

网络传递数据存在三个潜在问题:

(1)不同的实现以不同的格式存储二进制数,最常见的是大端字节序和小端字节序。

(2)不同的实现在存储相同的C数据类型上可能存在差异,例如32位系统中的long 为32位,64位系统中的long为64位。

(3)不同的实现给结构打包的方式存在差异,取决于各种数据类型所用的位数以及机器的对齐限制,因此,穿越套接字传送二进制结构绝不明智。

解决上述问题的两个常用方法:

(1)把所有的数值数据作为文本串来传递,前提是客户和服务器机器具有相同的字符集。

(2)显式定义所支持数据类型的二进制格式(位数,大端或小端字节序),并以这样的格式在客户与服务器之间传递所有数据。

 

 


这篇关于TCP客户/服务器程序实例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/337107

相关文章

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

客户案例:安全海外中继助力知名家电企业化解海外通邮困境

1、客户背景 广东格兰仕集团有限公司(以下简称“格兰仕”),成立于1978年,是中国家电行业的领军企业之一。作为全球最大的微波炉生产基地,格兰仕拥有多项国际领先的家电制造技术,连续多年位列中国家电出口前列。格兰仕不仅注重业务的全球拓展,更重视业务流程的高效与顺畅,以确保在国际舞台上的竞争力。 2、需求痛点 随着格兰仕全球化战略的深入实施,其海外业务快速增长,电子邮件成为了关键的沟通工具。

C++操作符重载实例(独立函数)

C++操作符重载实例,我们把坐标值CVector的加法进行重载,计算c3=c1+c2时,也就是计算x3=x1+x2,y3=y1+y2,今天我们以独立函数的方式重载操作符+(加号),以下是C++代码: c1802.cpp源代码: D:\YcjWork\CppTour>vim c1802.cpp #include <iostream>using namespace std;/*** 以独立函数

实例:如何统计当前主机的连接状态和连接数

统计当前主机的连接状态和连接数 在 Linux 中,可使用 ss 命令来查看主机的网络连接状态。以下是统计当前主机连接状态和连接主机数量的具体操作。 1. 统计当前主机的连接状态 使用 ss 命令结合 grep、cut、sort 和 uniq 命令来统计当前主机的 TCP 连接状态。 ss -nta | grep -v '^State' | cut -d " " -f 1 | sort |

Java Websocket实例【服务端与客户端实现全双工通讯】

Java Websocket实例【服务端与客户端实现全双工通讯】 现很多网站为了实现即时通讯,所用的技术都是轮询(polling)。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发 出HTTP request,然后由服务器返回最新的数据给客服端的浏览器。这种传统的HTTP request 的模式带来很明显的缺点 – 浏 览器需要不断的向服务器发出请求,然而HTTP

【Go】go连接clickhouse使用TCP协议

离开你是傻是对是错 是看破是软弱 这结果是爱是恨或者是什么 如果是种解脱 怎么会还有眷恋在我心窝 那么爱你为什么                      🎵 黄品源/莫文蔚《那么爱你为什么》 package mainimport ("context""fmt""log""time""github.com/ClickHouse/clickhouse-go/v2")func main(

2024.9.8 TCP/IP协议学习笔记

1.所谓的层就是数据交换的深度,电脑点对点就是单层,物理层,加上集线器还是物理层,加上交换机就变成链路层了,有地址表,路由器就到了第三层网络层,每个端口都有一个mac地址 2.A 给 C 发数据包,怎么知道是否要通过路由器转发呢?答案:子网 3.将源 IP 与目的 IP 分别同这个子网掩码进行与运算****,相等则是在一个子网,不相等就是在不同子网 4.A 如何知道,哪个设备是路由器?答案:在 A

图解TCP三次握手|深度解析|为什么是三次

写在前面 这篇文章我们来讲解析 TCP三次握手。 TCP 报文段 传输控制块TCB:存储了每一个连接中的一些重要信息。比如TCP连接表,指向发送和接收缓冲的指针,指向重传队列的指针,当前的发送和接收序列等等。 我们再来看一下TCP报文段的组成结构 TCP 三次握手 过程 假设有一台客户端,B有一台服务器。最初两端的TCP进程都是处于CLOSED关闭状态,客户端A打开链接,服务器端

828华为云征文|华为云Flexus X实例docker部署rancher并构建k8s集群

828华为云征文|华为云Flexus X实例docker部署rancher并构建k8s集群 华为云最近正在举办828 B2B企业节,Flexus X实例的促销力度非常大,特别适合那些对算力性能有高要求的小伙伴。如果你有自建MySQL、Redis、Nginx等服务的需求,一定不要错过这个机会。赶紧去看看吧! 什么是华为云Flexus X实例 华为云Flexus X实例云服务是新一代开箱即用、体

网络原理之TCP协议(万字详解!!!)

目录 前言 TCP协议段格式 TCP协议相关特性 1.确认应答 2.超时重传 3.连接管理(三次握手、四次挥手) 三次握手(建立TCP连接) 四次挥手(断开连接)  4.滑动窗口 5.流量控制 6.拥塞控制 7.延迟应答 8.捎带应答  9.基于字节流 10.异常情况的处理 小结  前言 在前面,我们已经讲解了有关UDP协议的相关知识,但是在传输层,还有