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实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

Spring组件实例化扩展点之InstantiationAwareBeanPostProcessor使用场景解析

《Spring组件实例化扩展点之InstantiationAwareBeanPostProcessor使用场景解析》InstantiationAwareBeanPostProcessor是Spring... 目录一、什么是InstantiationAwareBeanPostProcessor?二、核心方法解

java String.join()方法实例详解

《javaString.join()方法实例详解》String.join()是Java提供的一个实用方法,用于将多个字符串按照指定的分隔符连接成一个字符串,这一方法是Java8中引入的,极大地简化了... 目录bVARxMJava String.join() 方法详解1. 方法定义2. 基本用法2.1 拼接

Linux lvm实例之如何创建一个专用于MySQL数据存储的LVM卷组

《Linuxlvm实例之如何创建一个专用于MySQL数据存储的LVM卷组》:本文主要介绍使用Linux创建一个专用于MySQL数据存储的LVM卷组的实例,具有很好的参考价值,希望对大家有所帮助,... 目录在Centos 7上创建卷China编程组并配置mysql数据目录1. 检查现有磁盘2. 创建物理卷3. 创

Java List排序实例代码详解

《JavaList排序实例代码详解》:本文主要介绍JavaList排序的相关资料,Java排序方法包括自然排序、自定义排序、Lambda简化及多条件排序,实现灵活且代码简洁,文中通过代码介绍的... 目录一、自然排序二、自定义排序规则三、使用 Lambda 表达式简化 Comparator四、多条件排序五、

Java实例化对象的​7种方式详解

《Java实例化对象的​7种方式详解》在Java中,实例化对象的方式有多种,具体取决于场景需求和设计模式,本文整理了7种常用的方法,文中的示例代码讲解详细,有需要的可以了解下... 目录1. ​new 关键字(直接构造)​2. ​反射(Reflection)​​3. ​克隆(Clone)​​4. ​反序列化

SpringBoot快速搭建TCP服务端和客户端全过程

《SpringBoot快速搭建TCP服务端和客户端全过程》:本文主要介绍SpringBoot快速搭建TCP服务端和客户端全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录TCPServerTCPClient总结由于工作需要,研究了SpringBoot搭建TCP通信的过程

Python解决雅努斯问题实例方案详解

《Python解决雅努斯问题实例方案详解》:本文主要介绍Python解决雅努斯问题实例方案,雅努斯问题是指AI生成的3D对象在不同视角下出现不一致性的问题,即从不同角度看物体时,物体的形状会出现不... 目录一、雅努斯简介二、雅努斯问题三、示例代码四、解决方案五、完整解决方案一、雅努斯简介雅努斯(Janu

Python开发文字版随机事件游戏的项目实例

《Python开发文字版随机事件游戏的项目实例》随机事件游戏是一种通过生成不可预测的事件来增强游戏体验的类型,在这篇博文中,我们将使用Python开发一款文字版随机事件游戏,通过这个项目,读者不仅能够... 目录项目概述2.1 游戏概念2.2 游戏特色2.3 目标玩家群体技术选择与环境准备3.1 开发环境3

Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案

《Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案》:本文主要介绍Vue3组件中getCurrentInstance()获取App实例,但是返回nu... 目录vue3组件中getCurrentInstajavascriptnce()获取App实例,但是返回n