热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

TCP网络编程TCPC/S架构socketconnectsendrecvbindlistenaccept三次握手四次挥手多进程实现并发

TCP介绍、编程流程TCP回顾面向连接的流式协议;可靠,出错重传,且每收到一个数据给相应的确认通信之前建立链接服务器被动链接,
TCP 介绍、编程流程

  TCP 回顾


  •         面向连接的流式协议;
  •        可靠,出错重传,且每收到一个数据给相应的确认
  •        通信之前建立链接
    •        服务器被动链接,客户端主动链接

 

 TCP 与 UDP 的差异
 

TCP C/S 架构
 


TCP 编程-socket

    TCP 套接字创建



          UDP 套接字创建回顾
 

int sockfd;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd <0)
{perror("socket");exit(-1);
}

         创建 TCP 套接字
 

int sockfd;
sockfd &#61; socket(AF_INET, SOCK_STREAM, 0);
if(sockfd <0)
{perror("socket");exit(-1);
}

    做为客户端需要具备的条件


  •        知道“服务器”的ip&#xff0c;port
  •        主动连接“服务器”
  •        用到的函数

                   socket      创建“主动TCP套接字”

                  connect      连接“服务器”

                  send          发送数据到“服务器”

                  recv            接受“服务器”的响应

                  close        关闭连接


TCP 客户端-connect、send、recv

    connect 函数

/**function:* 主动跟服务器建立链接*parameter&#xff1a;* sockfd&#xff1a;socket套接字* addr&#xff1a; 连接的服务器地址结构* len&#xff1a; 地址结构体长度*return&#xff1a;* 成功&#xff1a;0* 失败&#xff1a;其他*note&#xff1a;* connect建立连接之后不会产生新的套接字* 连接成功后才可以开始传输TCP数据
*/
#include int connect(int sockfd, sonst struct sockadr *addr, socklen_t len);

  send 函数
 

/**function&#xff1a;* 发送数据*parameter&#xff1a;* sockfd&#xff1a; 已建立连接的套接字* buf&#xff1a; 发送数据的地址* nbytes&#xff1a; 发送缓数据的大小(字节为单位)* flags&#xff1a; 套接字标志&#xff08;常为0&#xff09;*return&#xff1a;* 成功&#xff1a;发送的字节数*note&#xff1a;* 不能用TCP协议发送 0 长度的数据包*/
#include ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags);

recv 函数
 

/**function&#xff1a;* 接收网络数据*paratemer&#xff1a;* sockfd&#xff1a; 套接字* buf: 接收网络数据的缓冲区的地址* nbytes: 接收缓冲区的大小&#xff08;字节为单位&#xff09;* flags: 套接字标志&#xff08;常为0&#xff09;*return:* 成功&#xff1a;接收到字节数*/
#include ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags);

 

客户端 code

#include
#include
#include
#include
#include
#include
#include int main(int argc, char *argv[])
{unsigned short port &#61; 8000; //服务器的端口号char *server_ip &#61; "172.20.226.11"; //服务器的IP//给main传参if(argc > 1) //函数参数&#xff0c;可以改服务器IP{server_ip &#61; argv[1];}if(argc > 2) //函数参数&#xff0c;可以改服务器端口号{port &#61; atoi(argv[2]);}//创建TCP套接字int sockfd &#61; 0;sockfd &#61; socket(AF_INET, SOCK_STREAM, 0); //创建通行端点&#xff1a;套接字if(sockfd <0){perror("socket");exit(-1);}//设置连接的IP&#xff0c;端口struct sockaddr_in server_addr;bzero(&server_addr, sizeof(server_addr)); //初始化服务器的地址server_addr.sin_family &#61; AF_INET;server_addr.sin_port &#61; htons(port);inet_pton(AF_INET, server_ip, &server_addr.sin_addr);//连接服务器int err_log &#61; connect(sockfd, (struct sockaddr *)&server_addr,sizeof(server_addr));if(err_log !&#61; 0){perror("connect");close(sockfd);exit(-1);}char send_buf[512] &#61; "";char recv_buf[512] &#61; "";printf("send data to %s&#xff1a;%d \n", server_ip,port);//发送消息printf("send");fgets(send_buf, sizeof(send_buf), stdin);send_buf[strlen(send_buf) - 1] &#61; 0; //除去‘\n’send(sockfd, send_buf, strlen(send_buf), 0); //向服务器发送数据//接收数据recv(sockfd, recv_buf, sizeof(recv_buf), 0); //接受服务器的响应printf("recv: %s \n",recv_buf);close(sockfd);}



TCP 服务器-bind、listen、accept

     做为 TCP 服务器需要具备的条件


  •       有一个确定的地址
  •        操作系统知道一个服务器
  •       等待连接的到来

   对于面向连接TCP协议来说&#xff0c;连接的建立才是数据通信的开始


      bind 示例

int err_log &#61; 0;
unsigned short port &#61; 8000;
struct sockaddr_in my_addr;bzero(&muy_addr, sizeof(my_addr));
my_addr.sin_family &#61; AF_INET;
my_addr.sin_port &#61; htons(port);
my_addr.sin_addr.s_addr &#61; htonl(INADDR_ANY);err_log &#61; bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr));
if(err_log !&#61; 0)
{perror("binding");close(sockfd);exit(-1);
}

      listen 函数

/*
功能:套接字由主动改为被动操作系统为套接字设置一个连续队列&#xff0c;用来记录所有连接到该套接字的连接参数&#xff1a;sockfd&#xff1a;socket监听套接字backlog&#xff1a;连接队列的长度返回值&#xff1a;成功&#xff1a;返回 0失败&#xff1a;其他
*/
#include int listen(int sockfd, int backlog);

     accept 函数

/*
功能&#xff1a;从已连接队列中取出一个已经建立的连接&#xff0c;如果没有任何连接可用&#xff0c;则进入睡眠等待&#xff08;阻塞&#xff09;参数&#xff1a;sockfd&#xff1a;socket 监听套接字cliaddr&#xff1a;用于存放客户端套接字地址结构addrlen&#xff1a;套接字地址结构体长度的地址返回值&#xff1a;已连接套接字注意&#xff1a;返回的是一个已连接套接字&#xff0c;该套接字代表当前这个连接*/
#include int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);

      TCP 服务器例子
 

#include
#include
#include
#include
#include
#include
#include int main(int argc, char *argv[])
{unsigned short port &#61; 8000;if(argc > 1){port &#61; atoi(argv[1]);}//创建TCP套接字int sockfd &#61; socket(AF_INET, SOCK_STREAM, 0);if(sockfd <0){perror("socket");exit(-1);}//组织本地信息struct sockaddr_in my_addr;bzero(&my_addr, sizeof(my_addr));my_addr.sin_family &#61; AF_INET;my_addr.sin_port &#61; htons(port);my_addr.sin_addr.s_addr &#61; htonl(INADDR_ANY);//绑定信息int err_log &#61; bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr));if(err_log !&#61; 0){perror("binding");close(sockfd);exit(-1);}//“主动”变“被动”err_log &#61; listen(sockfd, 10);if(err_log !&#61; 0){perror("listen");close(sockfd);exit(-1);}printf("listen client &poort &#61; %d...\n",port);while(1){struct sockaddr_in client_addr;char cli_ip[INET_ADDRSTRLEN] &#61;"";socklen_t cliaddr_len sizeof(client_addr);int connfd;//等待连接的到来connfd &#61; accept(sockfd, (struct sockaddr *)&client_addr, &cliaddr_len);if(connfd <0){perror("accept");continue;}//转换并打印信息inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);printf("--------------------------------\n");printf("client ip &#61; %s, port &#61; %d\n",cli_ip, ntohs(client_addr.sin_port));char recv_buf[2048] &#61; "";//接收消息while(recv(connfd, recv_buf, sizeof(recv_buf), 0) > 0){printf("\n recv data: \n");printf("%s\n",recv_buf);}close(connfd); //关闭已连接的套接字printf("client closed \n");}close(sockfd); //关闭监听的套接字return 0;
}


TCP 编程-close、三次握手、四次挥手

   close 关闭套接字


  •        使用close函数关闭套接字

                 关闭一个代表已连接套接字将导致另一端接收到一个0长度的数据包

  •        做服务器时

                    1      关闭监听套接字将导致服务器无法接收新的连接&#xff0c;但不影响已建立的连接

                    2     关闭accept返回已连接套接字将导致它代表的连接被关闭&#xff0c;但不会影响服务器的监听

  •        做客户端时

                 关闭连接就是关闭连接&#xff0c;不意味着其他

     三次握手

 


     四次挥手



TCP 并发服务器


     多进程实现并发

//#include <头文件>int main(int argc, char *argv[])
{//创建套接字sockfd//绑定&#xff08;bind&#xff09;套接字sockfd//监听&#xff08;listen&#xff09;套接字sockfdwhile(1){int connfd &#61; accept();if(fork() &#61;&#61; 0) //子进程{close(sockfd); //关闭监听套接字sockfdfun(); //服务客户端的具体事件在fun里实现close(connfd); //关闭已连接套接字connfdexit(0); //结束子进程}close(connfd); //关闭已连接套接字connfd}close(sockfd);return 0;
}

 


  多线程实现并发

//#include<头文件>int main(int argc, char *argv[])
{//创建套接字sockfd//绑定&#xff08;bind&#xff09;套接字sockfd//监听&#xff08;listen&#xff09;套接字sockfdwhile(1){int connfd &#61; accept();pthread_t tid;pthread_create(&tid, NULL, (void *)client_fun, (void *)connfd);pthread_detach(tid);}close(sockfd); //关闭监听套接字return 0;
}void *client_fun(void *arg)
{int connfd &#61; (int) arg;fun(); //服务与于客户端的具体程序close(connfd);
}


Web 服务器介绍

    web 服务器简介

         web服务器&#xff1a;

                www服务器&#xff0c;网站服务器

           特点&#xff1a;

                  使用HTTP协议与客户机浏览器进行信息交流

                 不仅存储信息&#xff0c;还可以在用户通过web浏览器提供的信息的基础上运行脚本和程序

                 该服务器可安装在UNIX&#xff0c;Linux&#xff0c;Windows等操作系统上

                著名的服务器有Apache&#xff0c;Tomcat&#xff0c;IIS

       HTTP 协议

             webserver    HTTP协议

                概念

                   一种详细规定了浏览器和万维网服务器之间互相通信的规则&#xff0c;通过因特网传送万维网文档的数据传送协议

               特点

  •            支持C/S架构
  •            简单快速&#xff1a;客户向服务器请求服务时&#xff0c;只传送请求方法和路径&#xff0c;常用GET&#xff0c;POST
  •            无连接&#xff1a;限制每次连接只处理一个请求
  •            无状态&#xff1a;如果后续处理需要前面的信息&#xff0c;它必须重传&#xff0c;这样可能导致每次连接传送的数据量增大

 

    Webserver 通信过程
 

 
 

 

推荐阅读
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 基于事件驱动的并发编程及其消息通信机制的同步与异步、阻塞与非阻塞、IO模型的分类
    本文介绍了基于事件驱动的并发编程中的消息通信机制,包括同步和异步的概念及其区别,阻塞和非阻塞的状态,以及IO模型的分类。同步阻塞IO、同步非阻塞IO、异步阻塞IO和异步非阻塞IO等不同的IO模型被详细解释。这些概念和模型对于理解并发编程中的消息通信和IO操作具有重要意义。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
author-avatar
aloneloveu2005
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有