1. socket套接字

(1)套接字简介

  ①socket是一种通讯机制,它包含一整套的调用接口和数据结构的定义,它给应用进程提供了使用如TCP/UDP等网络协议进行网络通讯的手段。

  ②Linux中的网络编程通过socket接口实现。socket是一种特殊的IO,提供对应的文件描述符

  ③一个完整的socket都有一个相关描述(协议、本地地址、本地端口、远程地址和远程端口等)。

  ④每一个套接字有一个本地的唯一socket,由操作系统分配。

(2)创建socket

头文件

#include <sys/socket.h>

函数

int socket(int domain, int type, int protocol);

参数

domain参数:

  ①AF_INET:   IPv4因特网域

  ②AF_INET6:  IPv6因特网域

  ③AF_UNIX:   unix域

  ④AF_UNSPEC: 未指定

type参数:

  ①SOCK_STREAM: 流式的套接字可以提供可靠的、面向连接的通讯流。它使用了TCP协议,TCP保证了数据传输的正确性和顺序性。

  ②SOCK_DGRAM:数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠及无差错。

  ③SOCK_RAW:原始套接字允许对低层协议(如IP或ICMP)直接访问,主要用于新的网络协议实现的测试等。

  ④SOCK_SEQPACKET: 长度固定、有序、可靠的面各连接报文传递。

protocol参数:通常为0,表示按给定的域和套接字类型选择默认协议。

功能

创建套接字

返回值

成功返回内核中消息队列的标识ID,出错返回-1

备注

套接字创建在内核中,若创建成功则返回内核文件描述表中的socket描述符。

2. 字节序、地址结构和IPv4地址族

(1)字节序

  ①不同体系结构的主机使用不同的字节序存储器来保存多字节整数。字节存储顺序不同,有的系统是高位在前,低位在后,而有的系统是低位在前,高位在后。

  ②字节序分为大端(高位存储于低地址,低位存储于高地址)小端(高位存储于高地址,低位存储于低地址)

  ③网络协议使用网络字节序,即大端字节序

(2)字节序转换函数

  ①uint32_t htonl(unit32_t hostlong); //将32位整数从主机字节序转为网络字节序

  ②uint16_t htons(unit16_t hostshort);//将16位整数从主机字节序转为网络字节序③uint32_t ntohl(unit32_t netlong); //将32位整数从网络字节序转为主机字节序  

  ④uint16_t ntohs(unit16_t netshort);//将16位整数从网络字节序转为主机字节序

(3)通用地址结构

头文件

#include <sys/socket.h>

结构体

struct sockaddr{

  unsigned short sa_family;  //internet地址族,AF_XXX

  char sa_data[14];          //14字节的协议地址

}

备注

①sa_data包含了一些远程电脑的地址、端口和套接字的数目,它里面的数据是杂溶在一起的。

②sa_family一般来说,IPv4使用AF_INET。

③在传递给需要地址结构的函数时,把指向该结构体的指针转换成(struct sockaddr*)传递进去。

(4)因特网地址结构(专用地址结构)

头文件

#include <sys/socket.h>

结构体

struct in_addr{   //其中的in指的是internet

  in_addr_t  s_addr   //ipv4地址

}

struct sockaddr_in{

  short int  sin_family;    //internet地址族,AF_XXX(主机字节序)

  unsigned short int sin_port; //端口号,16位(网络字节序)

  struct in_addr sin_addr;   //32位的IPv4地址(网络字节序)

  unsigned char sin_zero[8]; //添0(为了格式对齐的填充位)

}

备注

sockaddr和sockaddr_in这两个数据类型是等效的,可以相互转换,通常使用sockaddr_in更为方便。

(5)IPv4地址族和字符地址间的转换

头文件

#include <arp/inet.h>

函数1

const char* inet_ntop(int domain, const void* addr,

char* str, socklen_t size);//网络字节地址转为点分十进制

返回:成功返回地址字符串指针,出错返回NULL

函数2

int inet_pton(int domain, const char* str, void* addr);//点分转网络

返回:成功返回1,无效格式返回0,出错返回-1

参数

domain:Internet地址族,如AF_INET

addr: internet地址,32位IPv4地址(网络字节序)

str: 地址字符串(点分十进制)指针

size: 地址字符串大小

(6)填写IPv4地址族结构体案例

  1. struct sockaddr_in sin; //定义一个sockaddr_in结构体
  2. char buf[];
  3.  
  4. memset(&sin, , sizeof(sin));
  5. sin.sin_family = AF_INET; //填写Internet地址族
  6. sin.sin_port = htons((short)); //填写端口号(网络字节序)
  7.  
  8. //填充sin_addr
  9. if(inet_pton(AF_INET, "192.168.2.1", &sin.sin_addr.s_addr) <=){
  10. //错误处理
  11. }
  12.  
  13. printf("%s\n", inet_ntop(AF_INET, &sin.sin_addr.s_addr,buf, sizeof(buf)));

3. TCP编程模型

3.1 TCP通讯模型

(1)服务端调用序列

  ①调用socket函数创建套接字

  ②调用bind绑定本地地址和端口

  ③调用listen启动监听

  ④调用access从己连接队列中提取客户连接

  ⑤调用I/O函数(read/write)与客户端通讯

  ⑥调用close关闭套接字

(2)客户端调用序列

  ①调用socket函数创建套接字

  ②调用connect连接服务器端

  ③调用I/O函数(read/write)与服务器端通讯

  ④调用close关闭套接字

3.2 相关函数

(1)套接字与地址绑定

头文件

#include <sys/socket.h>

绑定地址

int bind(int sockfd, const struct sockaddr* addr, socklen_t len);

返回:成功返回0,出错返回-1

特特地址:#define INADDR_ANY  (uint32_t)0x00000000 //响应主机上的任何一个可用的IP地址。

查找绑定到套接字的地址

int getsockname(int sockfd, struct sockaddr* addr, socklen_t alenp)

返回:成功返回0,出错返回-1

获取对方地址

int getpeername(int sockfd, struct sockaddr* addr, socklen_t alenp)

返回:成功返回0,出错返回-1

(2)建立连接

头文件

#include <sys/socket.h>

服务器端

①int listen(int sockfd, int backlog);//backlog为指定进行客户端连接排队的队列长度。

返回:成功返回0,出错返回-1

②int accept(int sockfd, struct sockaddr* addr, socklen_t* len);

客户端

int connect(int sockfd, cosnt struct sockaddr* addr, socklen_t len)

返回:成功返回0,出错返回-1

【编程实验】获得服务器的时间

//time_tcp_server.c(服务端)

  1. #include <netdb.h>
  2. #include <sys/socket.h>
  3. #include <unistd.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <memory.h>
  7. #include <time.h>
  8. #include <signal.h>
  9.  
  10. /*获取服务器端的当前时间*
  11. 测试:telnet 127.0.0.1 xxxx
  12. http://xxx.xxx.xxx.xxx:端口号
  13. 注意:演示时可关闭服务器的防火墙,防止端口被过滤
  14. #service iptables status 查看防火墙
  15. #service iptables stop 关闭防火墙
  16. */
  17.  
  18. int sockfd;
  19. int bStop = ;
  20.  
  21. void sig_handler(int signo)
  22. {
  23. if(signo == SIGINT){
  24. bStop = ;
  25. printf("server close\n");
  26.  
  27. exit();
  28. }
  29. }
  30.  
  31. //显示客户端信息
  32. void out_addr(struct sockaddr_in* addr)
  33. {
  34. //将端口从网络字节序转换成主机字节序
  35. int port = ntohs(addr->sin_port);
  36. //获得IP地址
  37. char ip[] ={};
  38. //将ip地址从网络字节序转换成点分十分制
  39. inet_ntop(AF_INET, &addr->sin_addr.s_addr, ip, sizeof(ip));
  40.  
  41. printf("Client: %s(%d) connected\n", ip, port);
  42. }
  43.  
  44. //服务程序
  45. void do_service(int fd)
  46. {
  47. //获得系统时间
  48. long t = time();
  49. char* s = ctime(&t);
  50. size_t size = strlen(s) * sizeof(char);
  51.  
  52. //将服务器端获得的系统时间写回客户端
  53. if(write(fd, s, size) != size){
  54. perror("write error");
  55. }
  56. }
  57.  
  58. int main(int argc, char* argv[])
  59. {
  60. if(argc < ){
  61. printf("usage: %s port\n", argv[]);
  62. }
  63.  
  64. //按ctrl-c时中止服务端程序
  65. if(signal(SIGINT, sig_handler) == SIG_ERR){
  66. perror("signal sigint error");
  67. exit();
  68. }
  69.  
  70. /*步骤1:创建socket(套接字)
  71. *注:socket创建在内核中,是一个结构体
  72. *AF_INET:IPv4
  73. *SOCK_STREAM:tcp协议
  74. */
  75. sockfd = socket(AF_INET, SOCK_STREAM, );
  76.  
  77. /*步骤2:将sock和地址(包括ip、port)进行绑定*/
  78. struct sockaddr_in servAddr; //使用专用地址结构体
  79. memset(&servAddr, , sizeof(servAddr));
  80. //往地址中填入ip、port和Internet地址族类型
  81. servAddr.sin_family = AF_INET;//IPv4
  82. servAddr.sin_port = htons(atoi(argv[])); //port
  83. servAddr.sin_addr.s_addr = INADDR_ANY; //任一可用的IP
  84.  
  85. if(bind(sockfd, (struct sockaddr*)&servAddr, sizeof(servAddr)) < ){
  86. perror("bind error");
  87. exit();
  88. }
  89.  
  90. /*步骤3:调用listen函数启动监听
  91. * 通知系统去接受来自客户端的连接请求
  92. */
  93. if(listen(sockfd, ) < ){ //队列中最多允许10个连接请求
  94. perror("listen error");
  95. exit();
  96. }
  97.  
  98. /*步骤4:调用accept函数,从请求队列中获取一个连接
  99. * 并返回新的socket描述符
  100. * */
  101. struct sockaddr_in clientAddr;
  102. socklen_t clientAddr_len = sizeof(clientAddr);
  103. while(!bStop){
  104. //如果没有客户端连接,调用此函数后会阻塞,直至获得一个客户端连接
  105. int fd = accept(sockfd, (struct sockaddr*)&clientAddr, &clientAddr_len);
  106.  
  107. if(fd < ){
  108. perror("accept error");
  109. continue;
  110. }
  111.  
  112. //输出客户端信息
  113. out_addr(&clientAddr);
  114.  
  115. /*步骤5:调用IO函数(read/write)和客户端进行双向通信*/
  116. do_service(fd);
  117.  
  118. /*步骤6: 关闭fd套接字*/
  119. close(fd);
  120. }
  121.  
  122. close(sockfd);
  123.  
  124. return ;
  125. }
  126. /*输出结果
  127. * [root@localhost 13.TCP]# bin/time_tcp_server 8888
  128. * Client: 192.168.32.100(40672) connected
  129. * Client: 127.0.0.1(40608) connected
  130. * Client: 192.168.32.100(40674) connected
  131. */

//time_tcp_client.c(客户端)

  1. #include <netdb.h>
  2. #include <sys/socket.h>
  3. #include <unistd.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <memory.h>
  7.  
  8. int main(int argc, char* argv[])
  9. {
  10. if(argc < ){
  11. printf("usage: %s ip port\n", argv[]);
  12. exit();
  13. }
  14.  
  15. /*步骤1: 创建socket(套接字)*/
  16. int sockfd = socket(AF_INET, SOCK_STREAM, );
  17. if(sockfd < ){
  18. perror("socket error");
  19. }
  20.  
  21. //往servAddr中填入ip、port和地址族类型
  22. struct sockaddr_in servAddr;
  23. memset(&servAddr, , sizeof(servAddr));
  24. servAddr.sin_family = AF_INET;
  25. servAddr.sin_port = htons(atoi(argv[]));
  26. //将ip地址转换成网络字节序后填入servAdd中
  27. inet_pton(AF_INET, argv[], &servAddr.sin_addr.s_addr);
  28.  
  29. /*步骤2: 客户端调用connect函数连接到服务器端*/
  30. if(connect(sockfd, (struct sockaddr*)&servAddr, sizeof(servAddr)) < ){
  31. perror("connect error");
  32. exit();
  33. }
  34.  
  35. /*步骤3: 调用IO函数(read/write)和服务端进行双向通信*/
  36. char buffer[];
  37. memset(buffer, , sizeof(buffer));
  38. size_t size;
  39. if((size = read(sockfd, buffer, sizeof(buffer))) < ){
  40. perror("read error");
  41. }
  42.  
  43. if(write(STDOUT_FILENO, buffer, size) != size){
  44. perror("write error");
  45. }
  46.  
  47. /*关闭套接字*/
  48. close(sockfd);
  49. }
  50. /*输出结果
  51. [root@localhost 13.TCP]# bin/time_tcp_client 127.0.0.1 8888
  52. Fri Mar 17 16:35:57 2017
  53. */

第13章 TCP编程(1)_socket套接字的更多相关文章

  1. 第13章 TCP编程(4)_基于自定义协议的多线程模型

    7. 基于自定义协议的多线程模型 (1)服务端编程 ①主线程负责调用accept与客户端连接 ②当接受客户端连接后,创建子线程来服务客户端,以处理多客户端的并发访问. ③服务端接到的客户端信息后,回显 ...

  2. 第13章 TCP编程(3)_基于自定义协议的多进程模型

    5. 自定义协议编程 (1)自定义协议:MSG //自定义的协议(TLV:Type length Value) typedef struct{ //协议头部 ];//TLV中的T unsigned i ...

  3. 第13章 TCP编程(2)_TCP的连接和关闭过程

    4. TCP的连接和关闭过程 4.1 TCP连接的三次握手和四次挥手 (1)三次握手 ①第1次握手:建立连接.客户端发送连接请求报文段(SYN=1,sequence Number=x):然后客户端进入 ...

  4. Python黑帽编程2.8 套接字编程

    Python黑帽编程2.8 套接字编程 套接字编程在本系列教程中地位并不是很突出,但是我们观察网络应用,绝大多数都是基于Socket来做的,哪怕是绝大多数的木马程序也是如此.官方关于socket编程的 ...

  5. Unix网络编程--卷一:套接字联网API

    UNIX网络编程--卷一:套接字联网API 本书面对的读者是那些希望自己编写的程序能够使用成为套接字(socket)的API进行彼此通信的人. 目录: 0.准备环境 1.简介 2.传输层:TCP.UD ...

  6. Linux网络编程:原始套接字简介

    Linux网络编程:原始套接字编程 一.原始套接字用途 通常情况下程序员接所接触到的套接字(Socket)为两类: 流式套接字(SOCK_STREAM):一种面向连接的Socket,针对于面向连接的T ...

  7. VC++学习之网络编程中的套接字

    VC++学习之网络编程中的套接字 套接字,简单的说就是通信双方的一种约定,用套接字中的相关函数来完成通信过程.应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问 ...

  8. 网络编程与socket套接字

    网络编程与socket套接字 传输层 PORT协议 port是一种接口,数据通过它在计算机和其他设备(比如打印机,鼠标,键盘或监视器)之间,网络之间和其他直接连接的计算机之间传递 TCP协议 ​ 传输 ...

  9. 网络编程之基于tcp和udp的套接字

    一   udp协议网络编程 DNS:将域名解析成ip地址 SOCK_DGRAM:数据报协议,也是udp协议 udp协议的网络编程的一些用法: recvfrom:接收消息,接收的时一个元组,元组里面的元 ...

随机推荐

  1. Linux 内核链表实现和使用(一阴一阳,太极生两仪~)

    0. 概述 学习使用一下 linux 内核链表,在实际开发中我们可以高效的使用该链表帮我们做点事, 链表是Linux 内核中常用的最普通的内建数据结构,链表是一种存放和操作可变数据元 素(常称为节点) ...

  2. iconfont 入门级使用方法

    iconfont : what? 阿里妈妈MUX倾力打造的矢量图标管理.交流平台.设计师将图标上传到Iconfont平台,用户可以自定义下载多种格式的icon,平台也可将图标转换为字体,便于前端工程师 ...

  3. magento如何在首页显示产品

    1.首先现在magento后台创建一个新的分类,记下这个分类的 ID 号码.使用这个新建的分类来管理你的首页产品,这个分类设置为前台不可见.这样就不会显示在你的分类菜单中了,但使用代码调用的时候却会显 ...

  4. removeLineEndSpace

    /****************************************************************************** * removeLineEndSpace ...

  5. PHP CURL HTTPS内存泄露问题

    还原场景:通过一直运行脚本,向微信用户发送模板消息,发现运行了一段时间,内存就爆了,然后立马看了一下代码,发现跟其他的消息逻辑一模一样,唯一不一样的就是请求了微信的接口:然后继续开始找问题,发现当时使 ...

  6. sublime text 3 实用的快捷键

    Ctrl+Shift+P:打开命令面板Ctrl+P:搜索项目中的文件Ctrl+G:跳转到第几行Ctrl+W:关闭当前打开文件Ctrl+Shift+W:关闭所有打开文件Ctrl+Shift+V:粘贴并格 ...

  7. File、Directory、Path

    File.Directory.Path https://blog.csdn.net/xiaouncle/article/details/52050577 File.Directory.Path是实际开 ...

  8. LeetCode-Microsoft-Clone Graph

    Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors. OJ's ...

  9. 【转】python3中bytes和string之间的互相转换

    问题: 比对算法测试脚本在python2.7上跑的没问题,在python3上报错,将base64转码之后的串打印出来发现,2.7版本和3是不一样的:2.7就是字符串类型的,但是3是bytes类型的,形 ...

  10. Apache和Nginx的Rewrite规则对比

    一.Apache的rewrite 1.Rewrite规则简介: Rewirte主要的功能就是实现URL的跳转,它的正则表达式是基于Perl语言.可基于服务器级的(httpd.conf)和目录级的(.h ...