socket 编程

套接字概念

Socket本身有“插座”的意思,在Linux环境下,用于表示进程间网络通信的特殊文件类型。本质为内核借助缓冲区形成的伪文件。既然是文件,那么理所当然的,我们可以使用文件描述符引用套接字。与管道类似的,Linux系统将其封装成文件的目的是为了统一接口,使得读写套接字和读写文件的操作一致。区别是管道主要应用于本地进程间通信,而套接字多应用于网络进程间数据的传递。

在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程。“IP地址+端口号”就对应一个socket。欲建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socket pair就唯一标识一个连接。因此可以用Socket来描述网络连接的一对一关系。
套接字通信原理如下图所示:


网络字节序
我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分。网络数据流同样有大端小端之分,那么如何定义网络数据流的地址呢?TCP/IP协议规定,网络数据流应采用大端字节序,即低地址存高字节,高地址存低字节。
为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。

#include <arpa/inet.h>uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
//h表示host,n表示network,l表示32位长整数,s表示16位短整数。
//如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回,如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。

ip地址转换函数

只能处理IPv4的ip地址
不可重入函数
注意参数是struct in_addr

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp);
in_addr_t inet_addr(const char *cp);
char *inet_ntoa(struct in_addr in);

支持IPv4和IPv6
可重入函数
其中inet_pton和inet_ntop不仅可以转换IPv4的in_addr,还可以转换IPv6的in6_addr。

#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

网络套接字函数

socket模型流程图

socket函数

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
domain:AF_INET 这是大多数用来产生socket的协议,使用TCP或UDP来传输,用IPv4的地址AF_INET6 与上面类似,不过是来用IPv6的地址AF_UNIX 本地协议,使用在Unix和Linux系统上,一般都是当客户端和服务器在同一台及其上的时候使用
type:SOCK_STREAM 这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。SOCK_DGRAM 这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的连接。SOCK_SEQPACKET该协议是双线路的、可靠的连接,发送固定长度的数据包进行传输。必须把这个包完整的接受才能进行读取。SOCK_RAW socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)SOCK_RDM 这个类型是很少使用的,在大部分的操作系统上没有实现,它是提供给数据链路层使用,不保证数据包的顺序
protocol:传0 表示使用默认协议。
返回值:成功:返回指向新创建的socket的文件描述符,失败:返回-1,设置errno

bind函数

#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd:socket文件描述符
addr:构造出IP地址加端口号
addrlen:sizeof(addr)长度
返回值:成功返回0,失败返回-1, 设置errno服务器程序所监听的网络地址和端口号通常是固定不变的,客户端程序得知服务器程序的地址和端口号后就可以向服务器发起连接,因此服务器需要调用bind绑定一个固定的网络地址和端口号。
bind()的作用是将参数sockfd和addr绑定在一起,使sockfd这个用于网络通讯的文件描述符监听addr所描述的地址和端口号。前面讲过,struct sockaddr *是一个通用指针类型,addr参数实际上可以接受多种协议的sockaddr结构体,而它们的长度各不相同,所以需要第三个参数addrlen指定结构体的长度。如:
struct sockaddr_in servaddr;
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(6666);
首先将整个结构体清零,然后设置地址类型为AF_INET,网络地址为INADDR_ANY,这个宏表示本地的任意IP地址,因为服务器可能有多个网卡,每个网卡也可能绑定多个IP地址,这样设置可以在所有的IP地址上监听,直到与某个客户端建立了连接时才确定下来到底用哪个IP地址,端口号为6666。

listen函数

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
sockfd:socket文件描述符
backlog:排队建立3次握手队列和刚刚建立3次握手队列的链接数和
查看系统默认backlog
cat /proc/sys/net/ipv4/tcp_max_syn_backlog
典型的服务器程序可以同时服务于多个客户端,当有客户端发起连接时,服务器调用的accept()返回并接受这个连接,如果有大量的客户端发起连接而服务器来不及处理,尚未accept的客户端就处于连接等待状态,listen()声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接待状态,如果接收到更多的连接请求就忽略。listen()成功返回0,失败返回-1。

accept函数

#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
sockdf:socket文件描述符
addr:传出参数,返回链接客户端地址信息,含IP地址和端口号
addrlen:传入传出参数(值-结果),传入sizeof(addr)大小,函数返回时返回真正接收到地址结构体的大小
返回值:成功返回一个新的socket文件描述符,用于和客户端通信,失败返回-1,设置errno

connet函数

#include <sys/types.h>                     /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockdf:socket文件描述符
addr:传入参数,指定服务器端地址信息,含IP地址和端口号
addrlen:传入参数,传入sizeof(addr)大小
返回值:成功返回0,失败返回-1,设置errno

sockaddr数据结构
strcut sockaddr 很多网络编程函数诞生早于IPv4协议,那时候都使用的是sockaddr结构体,为了向前兼容,现在sockaddr退化成了(void *)的作用,传递一个地址给函数,至于这个函数是sockaddr_in还是sockaddr_in6,由地址族确定,然后函数内部再强制类型转化为所需的地址类型。

struct sockaddr {sa_family_t sa_family;      /* address family, AF_xxx */char sa_data[14];           /* 14 bytes of protocol address */
};struct sockaddr_in {__kernel_sa_family_t sin_family;          /* Address family */    地址结构类型__be16 sin_port;                          /* Port number */       端口号struct in_addr sin_addr;                 /* Internet address */  IP地址/* Pad to size of `struct sockaddr'. */unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -sizeof(unsigned short int) - sizeof(struct in_addr)];
};struct in_addr {                      /* Internet address. */__be32 s_addr;
};

socket API可以接受各种类型的sockaddr结构体指针做参数,例如bind、accept、connect等函数,这些函数的参数应该设计成void *类型以便接受各种类型的指针,但是sock API的实现早于ANSI C标准化,那时还没有void *类型,因此这些函数的参数都用struct sockaddr *类型表示,在传递参数之前要强制类型转换一下,例如:

struct sockaddr_in servaddr;
bind(listen_fd, (struct sockaddr *)&servaddr, sizeof(servaddr));        /* initialize servaddr */

简易版CS模型实现

客户端

服务端

注:以上的函数我都进行了简单的出错处理,所以将函数的首字母都大写以区别库函数。 以上就是非常简单的客户端与服务端通信程序。实现的功能就是字母大小写转换。。客户端输入小写字母,服务端将其改为对应的大写字母返回。

网络套接字编程(socket 详解)相关推荐

  1. 基本的TCP套接字编程(详解)

    目录 一.预备知识 1. 理解源IP地址和目的IP地址 2. 理解源端口号和目的端口号 3. 通过IP地址.端口号.协议号进行通信识别 4. 认识TCP协议和UDP协议 1.UDP的特点及目的 2.T ...

  2. 【Linux】网络基础+UDP网络套接字编程

    只做自己喜欢做的事情,不被社会和时代裹挟着前进,是一件很奢侈的事. 文章目录 一. 网络基础 1.局域网和广域网 2.协议初识和网络协议分层(TCP/IP四层模型) 3.MAC地址和IP地址(子网掩码 ...

  3. 什么是网络套接字(Socket)?

    什么是网络套接字(Socket)?一时还真不好回答,而且网络上也有各种解释,莫衷一是.下文将以本人所查阅到的资料来说明一下什么是Socket. Socket定义 Socket在维基百科的定义: A n ...

  4. 【网络篇】第五篇——网络套接字编程(一)(socket详解)

    socket编程 套接字概念 数据传输方式 ip地址转换函数 socket常见API sockaddr数据结构 socket缓冲区以及阻塞模式 LINUX下socket程序的演示 socket编程 套 ...

  5. 网络编程学习笔记-套接字编程-socket

    本文为了说明例子,用中文作为变量写在了程序里面,一般编程最好不要那么写 前置概念详见 本文目录 概念 基本TCP套接字编程 通信循环 半链接池 链接循环 udp协议 基于TCP协议实现远程执行客户端请 ...

  6. socket网络套接字编程

    目录 UDP通信程序的编写: udp通信流程*: 接口认识: 字节序转换接口*: 查看网络连接状态的命令: 实现构建思路: udp_srv.c: udp_socket.hpp: udp_client. ...

  7. 【Linux】网络套接字编程

    前言 在掌握一定的网络基础,我们便可以先从代码入手,利用UDP协议/TCP协议进行编写套接字程序,明白网络中服务器端与客户端之间如何进行连接并且通信的. 目录 一.了解源目的IP.端口.网络字节序.套 ...

  8. 《c语言从入门到精通》看书笔记——第16章 网络套接字编程(下)——套接字

    1.套接字概述 套接字是网络通信的基石,是网络通信的基本构件. 所谓套接字,实际上是一个指向传输提供者的句柄.在WinSock中,就是通过操作该句柄来实现网络通信和管理的.根据性质和作用不同,套接字可 ...

  9. Linux网络——套接字编程

    目录 基本知识 通信两端 查看网络信息 `sockaddr`结构 概念 介绍 辅助接口介绍 字节序转换接口 地址转换接口 UDP协议 概念 UDP通信流程 UDP通信接口 创建套接字 绑定地址信息 接 ...

最新文章

  1. Docker入门六部曲——基本引导
  2. Shell第一个脚本-添加用户
  3. Eigen矩阵的运算(二)
  4. python 打开当前目录的txt文件-Python - 读取其他文件夹/目录中的文本文件
  5. 乱谈数学--我理解的函数极限运算
  6. 终于理解了函数式技术
  7. java url下载ics_使用Microsoft Graph API处理外部(Internet / .ics)日历URL
  8. python多线程飞速写入文件
  9. 前端框架你究竟选什么
  10. Python基础-数据类型转换,默认参数,关键字参数
  11. Eclipse启动tomcat项目乱码而终端启动tomcat正常的解决办法
  12. C++:使用vector::reserve来避免不必要的重新分配
  13. matlab命令行运行,命令行运行matlab
  14. linux 屏幕录像软件,Linux_Linux下好用的5个屏幕录像软件,在很多时候,我们需要将在 Lin - phpStudy...
  15. PC端网页布局——世纪佳缘(二)页面初搭建
  16. 怎么快捷制作网站icon图标工具
  17. Xneomai 简介
  18. L2-027. 名人堂与代金券,结构体排序
  19. 麻烦你先搞懂这几个问题,简历再写熟悉数据库!!!
  20. Solr之——配置中文分词IKAnalyzer和拼音分词pinyinAnalyzer

热门文章

  1. 【解决方案】EasyCVR对接阿里云OSS助力泰国连锁超市老旧设备录像上云及云端实时监控
  2. 荣耀v8 android8,荣耀V8和荣耀8对比评测:荣耀V8真的会尴尬?
  3. 4G网速10倍于3G?内行人笑而不语
  4. 二叉树遍历(先序,中序,后序,层序)递归和非递归形式
  5. 公众号客服消息经常忘记看?简单设置,立即提醒查看!
  6. 关于黑客,距离一个程序员有多远?
  7. A brief introduction to weakly supervised learning(简要介绍弱监督学习)
  8. QCustomPlot系列(4)-时间轴做X轴-散点图-阶梯图
  9. 快递代收告别野蛮生长 “蓝店模式”正当时
  10. OpenWrt22.03版本docker不兼容解决方案