socket in Linux
socket in Linux
Socket编程界面由4BSD UNIX首先提出,目的是解决网间网进程通信问题。Socket接口为进程间通信提供了一种新的手段,它不但能用于同一机器中的进程之间的通信,而且支持网络通信功能。Socket具有类型,反应了对用户透明的通信特性。
一个完整的Socket连接用一个相关描述: { 协议,本地地址,本地端口,远地地址,远地端口 }
Socket 是面向客户-服务器模型而设计的,针对客户和服务器程序提供不同的Socket系统调用。
socket系统调用
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
Socket也具有一个类似于打开文件的函数调用Socket(),该函数返回一个整型的Socket描述符,随后 的连接建立、数据传输等操作都是通过该Socket实现的
- domain指明所使用的协议族,PF_INET,表示互联网协议族(TCP/IP协议族),PF_UNIX 本地协议
- type参数指定socket的类型:SOCK_STREAM 流式套接字 或 SOCK_DGRAM 数据报套接字,Socket接口还定义了原始Socket(SOCK_RAW),允许程序使用低层协议;
- protocol通常赋值"0"。
Socket()调用返回一个整型socket描述符,你可以在后面 的调用使用它。
使用socket的方法
下图是面向连接客户–服务器模型的典型时序图
服务器 客户
socket() socket()
bind() bind()
listen()
accept() 等待客户连接请求
阻塞 <━━━━━━━━━━━━━━━ connect()
read() <━━━━━━━━━━━━━━━> write()
1、创建socket
使用套接字函数socket创建,不过传递的参数与网络套接字不同,它会在内核创建一个struct socket实例。域参数应该是PF_LOCAL或者PF_UNIX,而不能用PF_INET之类。本地套接字的通讯类型应该是SOCK_STREAM或SOCK_DGRAM,协议为默认协议。该系统调用的返回值是一个socketid,protocol参数一般为0,表示默认协议。
#include <sys/socket.h>
int socket (int domain,int type, int protocol);
实际不止下面这些参数,在《UNIX网络编程》中介绍到可以访问ICMP、IP链路层的分组等可设置其它参数。
domain可选参数:AF 表示ADDRESS FAMILY 地址族、PF 表示PROTOCL FAMILY 协议族
域 | 描述 |
---|---|
AF_INET | IPv4 因特网域 |
AF_INET6 | |
AF_UNIX | |
AF_UPSPEC |
在windows中,AF_INET与PF_INET完全一样,而在Unix/Linux系统中,在不同的版本中这两者有微小差别。对于BSD,是AF,对于POSIX是PF**。理论上,建立socket时是指定协议,应该用PF_XXXX,设置地址时应该用AF_XXXX。**
type类型可选参数:
类型 | 描述 |
---|---|
SOCK_DGRAM | 固定长度的、无连接的、不可靠的报文传递 |
SOCK_RAM | IP协议的数据报接口 |
SOCK_SEQPACKET | 固定长度的、有序的、可靠地、面向连接的报文传递 |
SOCK_STREAM | 有序的、可靠地、双向的、面向连接的字节流 |
2、指定本地地址–绑定
将本地socket地址与所创建的socket联系起来,即将本socket地址赋予socket。bind()
的作用相当于给socket命名不同于网络套接字的绑定。本地套接字的绑定的是struct sockaddr_un
结构。struct sockaddr_un
结构有两个参数:sun_family
、sun_path
。sun_family
只能是AF_LOCAL
或AF_UNIX
,而sun_path
是本地文件的路径。通常将文件放在/tmp目录下。bind时需要注意:
- 绑定时,要注意绑定的地址的文件必须是系统中不存在的文件,且使用绝对路径
- 绑定的地址中的文件的访问权限最好是0777,然后按照当前umask进行修正
例如:
struct sockaddr_un sun;
sun.sun_family = AF_LOCAL;
strcpy(sun.sun_path, filepath);#include <sys/socket.h>//设置本端IP地址和端口
int bind (int sockfd, const struct sockaddr *addr, socklen_t len);//获取任何套接字本端IP地址和端口
int getsockname(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict alenp);//获取套接字上远端IP地址和端口
int getpeername(int sockfd, struct sockaddr *restrict addr,socklen_t *restrict alenp);
3、建立socket连接
connect()
与 accept()
这两个系统调用用于完成整个相关的建立。connect用于建立连接,accept用于面向连接的服务器。连接到一个正在监听的套接字之前,同样需要填充struct sockaddr_un
结构,然后调用connect函数。
//客户端
#include <sys/socket.h>//无连接的协议SOCK_DGRAM也可以使用它,这样就不用每次发送数据时指定IP地址;
int connect (int sockfd, const struct sockaddr *addr, socklen_t len);
- sockfd:调用socket()返回的fd;
- addr: 指向对方socket地址(信宿地址)结构的指针;
//服务端#include <sys/socket.h>/*
参数:backlog指定内核处于三次握手或者三次握手已经完成的连接队列大小;如果队列慢了将不会接受新的连接DOS攻击就是使用大量SYN分解把这个队列占满,导致正常连接无法进行;
说明:启动这个函数后,即使你不调用accept客户端也能完成三次握手
*/
int listen(int sockfd, int backlog);/*
说明:从已经完成三次握手的队列取出套接字,完成内核TCP状态的切换SYN_RCV--->ESTABLISHED
*/
int accept (int sockfd, struct sockaddr *restrict addr,socklen_t *restrict len);
4、发送数据 ---- write(),writev(),send()与sendto(),sendmsg()
用于socket数据发送的系统调用一共有五个,其中三个,write()、writev()和send()用于面向连接传输,其余两个用于无连接传输。面向连接的调用可以不指定信宿地址,而无连接的调用必须指定。假如无连接socket的双方均调用过connect(),可以认为是建立有连接的socket,也可以面向连接调用发送数据。
三个面向连接调用三者的格式大致相同:
- write (sockid,buff,bufflen) : 缓冲发送
- writev (sockid,iovector,vectorlen) : 集中发送
- send (sockid,buff,bufflen,flags) : 可控缓冲发送
其中buff指向发送缓冲区的指针,bufflen是发送缓冲区大小。
用于无连接数据发送的调用有两个:
- sendto (sockid,buff,bufflen,flags,dsadd,addrlen)
- sendmsg (sockid,message,flags):可控集中无连接发送
#include <sys/socket.h>/*这个函数参数跟write功能类似,但增加了一个flag参数;这个函数执行成功代表仅
仅将数据写入网卡驱动发送队列,而不是对方成功接收;
*/
ssize_t send(int sockfd, const void *buf, size_t len, int flag);//可以在无连接的套接字上发送数据;对于有连接的套接字,目标地址会被忽略
ssize_t sendto(int sockfd, const void *buf, size_t nbytes, int flag,const struct sockaddr *destaddr, socklen_t len);//下面这个发送函数可以指定多个缓冲区,与writev相似;它也面向无连接套接字
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flag);
5、接收数据 ---- read(),readv(),recv()与recvfrom(),recvmsg()
接收数据与发送数据系统调用是一一对应的,两者参数的最大区别是,前者buffer是一个指针,其所指单元初值为欲读数据长度,调用后的值是实际读出的值。
#include <sys/socket.h>//面向连接的套接字接收,类似read,但是多了个参数flag,可以接收特殊TCP数据
ssize_t recv(int sockfd, void *buf, size_t nbytes, int flag);//accept可以在连接时得到连接者的原地址,recvfrom可以在接收是同时得到发送者的原地址;
//对于有连接的套接字,等同于recv
ssize_t recvfrom (int sockfd, void *restrict buf, size_t len, int flag,struct sockaddr *restrict add,socklen_t *restrict addrlen);/*
功能:同时接收到多个数据报
返回值:返回数据的字节长度;若无可用数据,对方已经结束返回0,否则返回-1表示错误;
*/
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flag);
6、关闭socket
因为套接字是双工通信,所以可以单独关闭读或者写端,类似双工管道。
/*
功能:半关闭
参数:howSHUT_RDSHUT_WRSHUT_RDWR
*/
#include <sys/socket.h>
int shutdown (int sockfd, int how);//可以关闭linux所有文件描述符
int close(int sockfd);//同时关闭套接字的读写两端
int closesocket(int sockfd);
7、socket设置
套接字选项是进阶必备的知识,比如立即重用服务器监听端口、调整TCP窗口大小。各个协议的详细选项参加《UNIX网络编程》的150页。
#include <sys/socket.h>/*
功能:设置套接字选项
参数说明:level 协议层次IPPROT_TCP/IPPROT_IPoption 选项val 选项对应的值len 值的字节长度
*/
int setsockopt(int sockfd, int level, int option,const void* val,socklen_t len);int getsockopt(int sockfd, int level, int option, const void* val,socklen_t *restrict lenp);
本地socket和网络socket的区别:
域套接字关联的路径名应该是一个绝对路径名,千万不能使用相对路径名
调用connect连接一个域套接字设计的权限测试等同于调用open以只写方式访问相应的路径名
如果对于某个域套接字的connect调用发现这个监听套接字的队列已满,调用就立即返回一个ECONNREFUSED错误。
参考链接:
https://blog.csdn.net/qq_37414405/article/details/83690447
网络编程探究
并发模型参考:
socket in Linux相关推荐
- Windows Socket和Linux Socket编程的区别
2019独角兽企业重金招聘Python工程师标准>>> 1.一些常用函数的移植 http://www.vckbase.com/document/viewdoc/?id=1586 2. ...
- Fastsocket:高扩展性的 Socket 以及 Linux 内核的底层网络实现
目录 简介 安装编译 测试结果 GitHub README 介绍 参加者 安装 从源安装 开关内核 系统配置 用法 合适的场景### 如何使用 演示服务器 评价 Nginx的 HAProxy 在线评估 ...
- linux怎么连接两个服务器,一个服务器端同时创建两个socket连接 linux
不可不知 Linux操作系统网络服务器模型 Linux系统网络服务器模型主要有两种:并发服务器和循环服务器. 所谓并发服务器就是在同一个时刻可以处理来自多个客户端的请求;循环服务器是指服务器在同一时刻 ...
- 【网络编程入门】使用socket在Linux下实现即时通信软件
使用socket在Linux下实现即时通信软件 在前一篇文章中讲到了如何使用winsock:[网络编程入门]在C++中使用Windows TCP Sockets,也算是勉强入门了吧,接下来自己写一下在 ...
- java socket windows linux,socket在windows下和linux下的区别
windows到Linux代码移植遇到的问题 1.一些常用函数的移植http://www.vckbase.com/document/viewdoc/?id=1586 2.网络------转载& ...
- 【Socket】linux网络多路复用IO技术
1.mystery引入 1)Select是一种多路复用IO输入输出模式,在linux的输入输出编程中通过select的轮询机制,发现可用/可读或可写的接口. 2)低级socket程序中 ...
- linux c 多线程socket编程,Linux多线程socket编程一些心得
前段时间将新的web模型办到Linux上来,用epoll代替了IOCP,经测试确实性能提高了很多,吞吐量也寓所提高,对于Linux下面的网络编程不是三言两语就能说得透的了,加上多线程就更麻烦了,但是e ...
- 万用socket神器Linux Netcat 命令
netcat是网络工具中的瑞士军刀,它能通过TCP和UDP在网络中读写数据.通过与其他工具结合和重定向,你可以在脚本中以多种方式使用它.使用netcat命令所能完成的事情令人惊讶. netcat所做的 ...
- linux内核线程socket,从Linux源码看Socket(TCP)的accept
从Linux源码看Socket(TCP)的accept 前言 笔者一直以为若是能知道从应用到框架再到操做系统的每一处代码,是一件Exciting的事情. 今天笔者就从Linux源码的角度看下Serve ...
最新文章
- 不学无数——SpringBoot入门Ⅱ
- 1088 最长回文子串
- 项目初步验收需要检查事项
- 数据结构:平衡二叉树概念、旋转
- 安卓期末作品小项目_北京部编版八年级上册语文期末试卷
- C语言/找出任意两整数之间的素数以及他们的和
- 凤凰服务器系统,云服务器安装凤凰os
- 学校计算机社团都干些什么,计算机社团管理制度
- 四行代码创建复杂(无限级)树
- 北京python程序员求职_想找python程序员的工作,但发现稍微好点的职位都集中在北京。我非常想当python程序员,北京值得去吗?...
- Android性能提升之强引用、软引用、弱引用、虚引用使用
- 音视频技术 数字电视发展应用
- Parallel Stream 的错误实践
- 联想笔记本连不上手机热点_笔记本电脑连接不上手机热点该怎么解决?
- optionnally mysql_关于Tomcat与MySQL连接池问题的解析!
- 【Domoticz】玩转Domoticz平台——配合ESPEasy固件,开个头,以后玩起来起来再更新博客
- Photoshop支持ICO图片格式(咋个办呢 zgbn)
- 如何使用 Diago 诊断 Go 程序中的 CPU 和内存使用情况
- 串口控制小车电机转动+蓝牙长按控制
- java计算机毕业设计中学招生管理系统源码+数据库+系统+lw文档+mybatis+运行部署