热门标签 | 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 通信过程
 

 
 

 

推荐阅读
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社区 版权所有