网络协议(二) Socket

  • 6. socket
    • 6.1 socket 简介
    • 6.2 socket 特点
    • 6.3 socket 对比 HTTP
    • 6.4 socket 建立连接过程
    • 6.5 socket 建立连接代码实现
      • 6.5.1 客户端代码
      • 6.5.2 服务器端代码

6. socket

6.1 socket 简介

socket是为了实现以上的通信过程而建立成来的通信管道,其真实的代表是客户端和服务器端的一个通信进程,双方进程通过socket进行通信,而通信的规则采用指定的协议。
socket只是一种连接模式,不是协议,socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。tcp、udp,简单的说(虽然不准确)是两个最基本的协议,很多其它协议都是基于这两个协议如,http就是基于tcp的,.用socket可以创建tcp连接,也可以创建udp连接,这意味着,用socket可以创建任何协议的连接,因为其它协议都是基于此的。

6.2 socket 特点

socket 优点 缺点
socket 传输数据为字节级,传输数据可自定义,数据量小(对于手机应用讲:费用低) 需对传输的数据进行解析,转化成应用级的数据
socket 传输数据时间短,性能高 对开发人员的开发水平要求高
socket 适合于客户端和服务器端之间信息实时交互 相对于Http协议传输,增加了开发量
socket 可以加密,数据安全性强

6.3 socket 对比 HTTP

6.4 socket 建立连接过程

  • 在前面已经讲解过了TCP的三次握手建立连接,四次挥手断开连接的过程。
    这里socket的建立连接和断开连接起始就是这个过程的代码实现。

  • 回顾tcp三次握手过程

    1. 第一次握手:客户端尝试连接服务器,向服务器发送syn包,syn=j,客户端进入SYN_SEND状态等待服务器确认

    2. 第二次握手:服务器接收客户端syn包并确认(ack=j+1),同时向客户端发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态

    3. 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手

流程图:

  • 根据tcp的三次握手,socket也定义了三次握手,也许是参考tcp的三次握手,一些计算机大神们画出了socket的三次握手的模型图

  • socket建立连接客户端流程

(1)打开一通信通道,并连接到服务器所在主机的特定端口;
(2)向服务器发服务请求报文,等待并接收应答;继续提出请求…
(3)请求结束后关闭通信通道并终止。

  • socket建立连接服务器端流程

(1)打开一通信通道并告知本地主机,它愿意在某一公认地址上的某端口(如FTP的端口可能为21)接收客户请求;
(2)等待客户请求到达该端口;
(3)接收到客户端的服务请求时,处理该请求并发送应答信号。接收到并发服务请求,要激活一新进程来处理这个客户请求(如UNIX系统中用fork、exec)。新进程处理此客户请求,并不需要对其它请求作出应答。服务完成后,关闭此新进程与客户的通信链路,并终止。
(4)返回第(2)步,等待另一客户请求。
(5)关闭服务器

6.5 socket 建立连接代码实现

6.5.1 客户端代码

  • swift代码
 dispatch_sync(dispatch_get_global_queue(0, 0), ^{// 处理耗时操作的代码块...// 创建socket/*1.AF_INET: ipv4 执行ip协议的版本2.SOCK_STREAM:指定Socket类型,面向连接的流式socket 传输层的协议3.IPPROTO_TCP:指定协议。 IPPROTO_TCP 传输方式TCP传输协议返回值 大于0 创建成功*/_clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);// 建立连接(与服务器)/*终端里面 命令模拟服务器 netcat  nc -lk 12345参数一:套接字描述符参数二:指向数据结构sockaddr的指针,其中包括目的端口和IP地址参数三:参数二sockaddr的长度,可以通过sizeof(struct sockaddr)获得返回值 int -1失败 0 成功*/struct sockaddr_in addr;/* 填写sockaddr_in结构*/addr.sin_family = AF_INET;addr.sin_port=htons(8080);addr.sin_addr.s_addr = inet_addr("192.168.0.99");int connectResult = connect( _clientSocket, (const struct sockaddr *)&addr, sizeof(addr));// 发送数据(到服务器)/*第一个参数指定发送端套接字描述符;第二个参数指明一个存放应用程式要发送数据的缓冲区;第三个参数指明实际要发送的数据的字符数;第四个参数一般置0。成功则返回实际传送出去的字符数,失败返回-1,*/char * str = "itcast";ssize_t sendLen = send( _clientSocket, str, strlen(str), 0);// 接送数据(从服务器)/*第一个参数socket第二个参数存放数据的缓冲区第三个参数缓冲区长度。第四个参数指定调用方式,一般置0返回值 接收成功的字符数*/char *buf[1024];ssize_t recvLen = recv( _clientSocket, buf, sizeof(buf), 0);NSLog(@"---->%ld",recvLen);});
//    [self test];
}
  • c 语言实现代码
#include<stdio.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<string.h>
#include<unistd.h>
#define BUFFER_SIZE 1024  int main(int argc, const char * argv[])
{  struct sockaddr_in server_addr;  server_addr.sin_family = AF_INET;  server_addr.sin_port = htons(11332);  server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  bzero(&(server_addr.sin_zero), 8);  int server_sock_fd = socket(AF_INET, SOCK_STREAM, 0);  if(server_sock_fd == -1)  {  perror("socket error");  return 1;  }  char recv_msg[BUFFER_SIZE];  char input_msg[BUFFER_SIZE];  if(connect(server_sock_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in)) == 0)  {  fd_set client_fd_set;  struct timeval tv;  while(1)  {  tv.tv_sec = 20;  tv.tv_usec = 0;  FD_ZERO(&client_fd_set);  FD_SET(STDIN_FILENO, &client_fd_set);  FD_SET(server_sock_fd, &client_fd_set);  select(server_sock_fd + 1, &client_fd_set, NULL, NULL, &tv);  if(FD_ISSET(STDIN_FILENO, &client_fd_set))  {  bzero(input_msg, BUFFER_SIZE);  fgets(input_msg, BUFFER_SIZE, stdin);  if(send(server_sock_fd, input_msg, BUFFER_SIZE, 0) == -1)  {  perror("发送消息出错!\n");  }  }  if(FD_ISSET(server_sock_fd, &client_fd_set))  {  bzero(recv_msg, BUFFER_SIZE);  long byte_num = recv(server_sock_fd, recv_msg, BUFFER_SIZE, 0);  if(byte_num > 0)  {  if(byte_num > BUFFER_SIZE)  {  byte_num = BUFFER_SIZE;  }  recv_msg[byte_num] = '\0';  printf("服务器:%s\n", recv_msg);  }  else if(byte_num < 0)  {  printf("接受消息出错!\n");  }  else  {  printf("服务器端退出!\n");  exit(0);  }  }  }  //}  }  return 0;
} 

6.5.2 服务器端代码

#include<stdio.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<string.h>
#include<unistd.h>
#define BACKLOG 5     //完成三次握手但没有accept的队列的长度
#define CONCURRENT_MAX 8   //应用层同时可以处理的连接
#define SERVER_PORT 11332
#define BUFFER_SIZE 1024
#define QUIT_CMD ".quit"
int client_fds[CONCURRENT_MAX];
int main(int argc, const char * argv[])
{  char input_msg[BUFFER_SIZE];  char recv_msg[BUFFER_SIZE];  //本地地址  struct sockaddr_in server_addr;  server_addr.sin_family = AF_INET;  server_addr.sin_port = htons(SERVER_PORT);  server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  bzero(&(server_addr.sin_zero), 8);  //创建socket  int server_sock_fd = socket(AF_INET, SOCK_STREAM, 0);  if(server_sock_fd == -1)  {  perror("socket error");  return 1;  }  //绑定socket  int bind_result = bind(server_sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));  if(bind_result == -1)  {  perror("bind error");  return 1;  }  //listen  if(listen(server_sock_fd, BACKLOG) == -1)  {  perror("listen error");  return 1;  }  //fd_set  fd_set server_fd_set;  int max_fd = -1;  struct timeval tv;  //超时时间设置  while(1)  {  tv.tv_sec = 20;  tv.tv_usec = 0;  FD_ZERO(&server_fd_set);  FD_SET(STDIN_FILENO, &server_fd_set);  if(max_fd <STDIN_FILENO)  {  max_fd = STDIN_FILENO;  }  //printf("STDIN_FILENO=%d\n", STDIN_FILENO);  //服务器端socket  FD_SET(server_sock_fd, &server_fd_set);  // printf("server_sock_fd=%d\n", server_sock_fd);  if(max_fd < server_sock_fd)  {  max_fd = server_sock_fd;  }  //客户端连接  for(int i =0; i < CONCURRENT_MAX; i++)  {  //printf("client_fds[%d]=%d\n", i, client_fds[i]);  if(client_fds[i] != 0)  {  FD_SET(client_fds[i], &server_fd_set);  if(max_fd < client_fds[i])  {  max_fd = client_fds[i];  }  }  }  int ret = select(max_fd + 1, &server_fd_set, NULL, NULL, &tv);  if(ret < 0)  {  perror("select 出错\n");  continue;  }  else if(ret == 0)  {  printf("select 超时\n");  continue;  }  else  {  //ret 为未状态发生变化的文件描述符的个数  if(FD_ISSET(STDIN_FILENO, &server_fd_set))  {  printf("发送消息:\n");  bzero(input_msg, BUFFER_SIZE);  fgets(input_msg, BUFFER_SIZE, stdin);  //输入“.quit"则退出服务器  if(strcmp(input_msg, QUIT_CMD) == 0)  {  exit(0);  }  for(int i = 0; i < CONCURRENT_MAX; i++)  {  if(client_fds[i] != 0)  {  printf("client_fds[%d]=%d\n", i, client_fds[i]);  send(client_fds[i], input_msg, BUFFER_SIZE, 0);  }  }  }  if(FD_ISSET(server_sock_fd, &server_fd_set))  {  //有新的连接请求  struct sockaddr_in client_address;  socklen_t address_len;  int client_sock_fd = accept(server_sock_fd, (struct sockaddr *)&client_address, &address_len);  printf("new connection client_sock_fd = %d\n", client_sock_fd);  if(client_sock_fd > 0)  {  int index = -1;  for(int i = 0; i < CONCURRENT_MAX; i++)  {  if(client_fds[i] == 0)  {  index = i;  client_fds[i] = client_sock_fd;  break;  }  }  if(index >= 0)  {  printf("新客户端(%d)加入成功 %s:%d\n", index, inet_ntoa(client_address.sin_addr), ntohs(client_address.sin_port));  }  else  {  bzero(input_msg, BUFFER_SIZE);  strcpy(input_msg, "服务器加入的客户端数达到最大值,无法加入!\n");  send(client_sock_fd, input_msg, BUFFER_SIZE, 0);  printf("客户端连接数达到最大值,新客户端加入失败 %s:%d\n", inet_ntoa(client_address.sin_addr), ntohs(client_address.sin_port));  }  }  }  for(int i =0; i < CONCURRENT_MAX; i++)  {  if(client_fds[i] !=0)  {  if(FD_ISSET(client_fds[i], &server_fd_set))  {  //处理某个客户端过来的消息  bzero(recv_msg, BUFFER_SIZE);  long byte_num = recv(client_fds[i], recv_msg, BUFFER_SIZE, 0);  if (byte_num > 0)  {  if(byte_num > BUFFER_SIZE)  {  byte_num = BUFFER_SIZE;  }  recv_msg[byte_num] = '\0';  printf("客户端(%d):%s\n", i, recv_msg);  }  else if(byte_num < 0)  {  printf("从客户端(%d)接受消息出错.\n", i);  }  else  {  FD_CLR(client_fds[i], &server_fd_set);  client_fds[i] = 0;  printf("客户端(%d)退出了\n", i);  }  }  }  }  }  }  return 0;
} 

网络协议(二) Socket相关推荐

  1. 网络协议 11 - Socket 编程(下):眼见为实耳听为虚

    网络协议 11 - Socket 编程(下):眼见为实耳听为虚 原文:网络协议 11 - Socket 编程(下):眼见为实耳听为虚 系列文章传送门: 网络协议 1 - 概述 网络协议 2 - IP ...

  2. 网络协议之:socket协议详解之Datagram Socket

    文章目录 简介 什么是Datagram Socket 使用socat来创建UDP服务 使用ss命令来监控Datagram Sockets 使用nc建立和UDP Socket的连接 总结 简介 上一篇文 ...

  3. 网络协议之:socket协议详解之Socket和Stream Socket

    文章目录 简介 Socket是什么 Stream Socket 使用socat创建一个TCP服务器 使用ss检查TCP连接 使用nc连接socket 总结 简介 不管是在普通的网络编程中还是在nett ...

  4. 网络协议之:socket协议详解之Unix domain Socket

    文章目录 简介 什么是Unix domain Socket 使用socat来创建Unix Domain Sockets 使用ss命令来查看Unix domain Socket 使用nc连接到Unix ...

  5. 网络协议之socket协议详解之Unix domain Socket

    简介 之前的文章我们讲到了Socket中的Stream Socket和Datagram Socket,和有连接的Stream Socket不同,Datagram Socket是无连接的.有连接的Str ...

  6. 网络协议 11 - Socket 编程(下)

    之前我们基本了解了网络通信里的大部分协议,一直都是在"听"的过程.很多人都会觉得,好像看懂了,但关了页面回忆起来,好像又什么都没懂.这次咱们就"真枪实弹"的码起 ...

  7. 网络协议(十四):WebSocket、WebService、RESTful、IPv6、网络爬虫、HTTP缓存

    网络协议系列文章 网络协议(一):基本概念.计算机之间的连接方式 网络协议(二):MAC地址.IP地址.子网掩码.子网和超网 网络协议(三):路由器原理及数据包传输过程 网络协议(四):网络分类.IS ...

  8. 网络协议OSI、TCP/IP协议、Socket套接字和第三方AsyncSock的使用等解析

    一.网络协议定义 1.OSI参考模型:全称(Open System Interconnection), 开放式系统互联参考模型.是一个逻辑上的定义,一个规范,它把网络协议从逻辑上分为七层,只要目的是为 ...

  9. 趣谈网络协议笔记-二(第十三讲)

    趣谈网络协议笔记-二(第十三讲) 套接字Socket:Talk is cheap, show me the code 前言 这只是笔记,是为了整理刘超大神的极客时间专栏的只是而存在的! 经常会在网络上 ...

最新文章

  1. http status 404 – 未找到_HTTP状态码
  2. Genymotion 模拟器 VirtualBox
  3. Android监听程序自身被卸载
  4. nonce和timestamp在Http安全协议中的作用
  5. spark task和stage划分原理
  6. VTK:InfoVis之KMeansClustering
  7. Exchange 邮件投递被拒的问题分析
  8. 嵌套集合模型(Nested set model)介绍
  9. 阶乘和(信息学奥赛一本通-T1173)
  10. js学习 字符串常用方法
  11. css的font修改颜色,css的font字体颜色如何设置
  12. 关于PPPOE拨号分配给用户32位掩码,且IP与网关相同的问题
  13. HTML学生个人网站作业设计:动漫网站设计——蜡笔小新(9页) HTML+CSS+JavaScript 简单DIV布局个人介绍网页模板代码 DW学生个人网站制作成品下载
  14. 厉害了,Pandas表格还能五彩斑斓的展示数据,究竟是怎么做到的呢?
  15. c语言句子后移两位加密,用C语言实现对输入的引英文句子进行加密
  16. 基于javaweb+mysql的超市进销存管理系统(java+SpringBoot+Html+Layui+echarts+mysql)
  17. 测试正则表达式的小方法
  18. Java基础-Java概述(第一、二章)
  19. 阿里的“无用”和“有用”
  20. OPENGL-学习计算机图形学

热门文章

  1. 好莱坞美剧电影英雄主义价值观的问题
  2. 计算机音乐谱夜空中最亮的星歌词,夜空中最亮的星歌谱及歌词
  3. 中国医学计算机成级别像杂志,中国医学计算机成像杂志怎么样,审稿时间
  4. 华为设备常见SNMP操作
  5. 购买重疾险的十大误区(建议收藏)
  6. 教学妹开发springboot+vue的博客论坛系统,so esay
  7. 饥饿营销:如果世界末日来临,你愿意为我抢一件优衣库kwas联名款吗?
  8. mongo-go-driver 踩坑心得 server selection error
  9. TCP/IP协议,HTTP协议,get和post请求的关联与区别
  10. 计算机人工智能专业大一新生书单及电影