Linux Socket基础介绍
Linux Socket函数库是从Berkeley大学开发的BSD UNIX系统中移植过来的。BSD Socket接口是众多Unix系统中被广泛支持的TCP/IP通信接口,Linux下的Socket程序设计,除了微小的差别之外,也适用于大多数其它Unix系统。
Socket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序。网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。
Socket的使用和文件操作比较类似。如同文件的读、写、打开、关闭等操作一样,TCP/IP网络通信同样也有这些操作,不过它使用的接口不是文件描述符或者FILE*,而是一个称做Socket的描述符。类似于文件操作,对于Socket,也通过读、写、打开、关闭操作来进行网络数据传送。同时,还有一些辅助的函数,如域名/IP地址查询、Socket功能设置等。
套接字有三种类型:流式套接字、数据报套接字及原始套接字。
流式套接字定义了一种可靠的面向连接的服务,实现了无差错无重复的顺序数据传输。数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠、无差错。原始套接字允许对底层协议如IP或ICMP直接访问,主要用于新的网络协议实现的测试等。
套接字工作过程如下:服务器首先启动,通过调用socket()建立一个套接字,然后调用bind()将该套接字和本地网络地址联系在一起,再调用listen()使套接字做好侦听的准备,并规定它的请求队列的长度,之后就调用accept()来接收连接。客户在建立套接字后就可以调用connect()和服务器建立连接。连接一旦建立,客户机和服务器之间就可以通过调用read()和write()来发送和接收数据。最后,待数据传送结束后,双方调用close()关闭套接字。
Socket函数库:
1. socket(int domain, int type,int protocol):此函数分配一个Socket句柄,用于指定特定网络下,使用特定的协议和数据传送方式进行通信。Socket句柄分配以后,如果要开始TCP通信,还需要建立连接。根据需要,可以主动地建立连接(通过connect())和被动地等待对方建立连接(通过listen()),在连接建立后才能使用读写操作通过网络连接进行数据交换。
domain参数选择通信中使用的协议族,也就是网络的类型,可以是以下之一:(1)、AF_UNIX:UNIX内部协议;(2)、AF_INET:ARPA Internet协议,也就是TCP/IP协议族;(3)、AF_ISO:ISO协议;(4)、AF_NS:Xerox Network Systems协议;(5)、AF_IMPLINK:IMP “host at IMP” link layer。
type参数为数据传送的方式,可以是以下之一:(1)、SOCK_STREAM:保证顺序的、可靠传送的双向字节数据流,最为常用,也是TCP连接所使用的方式;(2)、SOCK_DGRAM:无连接的、不保证可靠的、固定长度(通常很小)的消息传送;(3)、SOCK_SEQPACKET:顺序的、可靠的双向固定长度的数据报传送,只用于AF_NS类型的网络中;(4)、SOCK_RAW:原始的数据传送,适用于系统内部专用的网络协议和接口,和SOCK_RDM一样,只能由超级用户使用;(5)、SOCK_RDM:可靠的数据报传送,未实现。
protocol参数指定通信中使用的协议。在给定Socket的协议族和传送类型之后,一般情况下所使用的协议也就固定下来,此时protocol参数可使用缺省值”0”。但如果还有多个协议供选择,则必须使用protocol参数来标识。
socket()函数,正常执行时,返回Socket描述符;否则,返回-1,错误状态在全局变量errno中。
2. close(int fd):Socket和文件描述符的关闭操作都是使用这个函数。fd参数为Socket描述符。返回值,正常是返回0,-1表示出错。
3. bind(int sockfd, structsockaddr *my_addr, int addrlen):此函数给已经打开的Socket指定本地地址。这个函数的使用有以下两种情况:(1)、如果此Socket是面向连接的,而且此Socket在连接建立过程中处于被动的地位,即,乙方程序使用listen函数等待对方建立连接,对方用connect函数来向此Socket建立连接,这种情况下,必须用bind给此Socket设定本地地址。在乙方使用listen函数时,除指定Socket描述符之外,该Socket必须已经用bind函数设定好了本地地址(包括IP地址和端口号),这样,系统在收到建立连接的网络请求时,才能根据请求的目的地址,识别是通向哪个Socket的连接,从而乙方才能用此Socket接收到发给此Socket地址的数据包。不指定Socket的本地地址,就无法将此Socket用于连接建立和数据接收。(2)、如果此Socket用于无连接的情形,同样也要求给该Socket设定本地地址,这样,以后系统从网络中接收到数据后,才知道该送给哪个Socket及其相对应的进程。
sockfd参数:用于指定Socket描述符。
addrlen参数:my_addr结构的长度。
my_addr参数:用于侦听连接请求的本地地址。struct sockaddr是一个通用性的结构,不仅包含TCP/IP协议的情况,同时也是为了适合于其它网络,如AF_NS。由于它的这种通用性,它只是定义了一个一般意义上的存储空间。
bind函数返回值:正常时返回0,否则返回-1,同时errno是系统错误码。
4. listen(int s, int backlog):准备接收连接请求。在用bind()给一个Socket设定本地地址后,就可以将这个Socket用于接收连接请求,即listen()。调用listen()之后,系统将给此Socket配备一个连接请求的队列,暂存系统接收到的、申请向此Socket建立连接的请求,等待用户程序用accept()正式接收该请求。队列长度,就由backlog参数指定。如果短时间内向乙方建立连接的请求过多,乙方来不及处理,那么排在backlog之后的请求将被系统拒绝。因此,backlog参数实际上规定了乙方程序能够容许的连接建立处理速度。至于乙方程序使用此Socket(及其指定的本地地址)实际建立连接的个数,由乙方程序调用accept()的次数来决定。
listen函数返回值:正常时返回0,否则返回-1.
5. accept(int s, struct sockaddr*addr, int *addrlen):接受指定Socket上的连接请求。在调用listen()之后,系统就在Socket的连接请求暂存队列里存放每一个向该Socket(及其本地地址)建立的连接请求。accept()函数的作用就是,从该暂存队列中取出一个连接请求,用该Socket的数据,创建一个新的Socket:Socket_New,并为它分配一个文件描述符。Socket_New即标识了此次建立的连接,可被乙方用来向连接的另一方发送和接收数据(write/read, send/recv)。同时,原Socket仍然保持打开状态不变,继续用于等待网络连接请求。
如果该Socket的暂存队列中没有待处理的连接请求,根据Socket的特征选项(是否non_blocking),blocking即阻塞,accept()函数将选择两种方式:如果该Socket不是non_blocking型的,accept()将一直等待,直到收到一个连接请求后才返回;如果该Socket是non_blocking型的,那么accept()将立即返回,但如果没有连接请求,只返回错误信息,不创建新的Socket_New。accept()返回后,如果创建了新的Socket_New来标识新建立的连接,那么参数addr指定的结构里面将会有对方的地址信息,addrlen是地址信息的长度。
s参数:Socket描述符。
addr参数:accept()接受连接后,在addr指向的结构中存放对方的地址信息。如果是AF_INET Socket,该地址信息就是地方的IP地址和端口号。
addrlen参数:在调用accept()之前,*addrlen必须被设置为addr数据结构的合法长度。在accept()返回之后,*addrlen中是对方地址信息的长度。
accept函数返回值:如果正常创建了一个新的连接,那么返回非负的整数,即新连接的Socket描述符(注意,用于等待连接请求的原Socket保持打开状态不变,可用于接收新的连接请求),否则,返回-1.
bind、listen、accept等函数,都是用于被动地等待对方建立连接时需要使用的,而connect函数,则是主动地向对方建立连接时使用的。connect()使用一个事先打开的Socket,和目的方(即通信对方,或称服务器一方)地址信息,向对方发出连接建立请求。
6. connect(int sockfd, structsockaddr *serv_addr, int addrlen):客户端发送服务请求。
sockfd参数:socket函数返回的socket描述符。
serv_addr:存储远程计算机的IP地址和端口信息的结构。
addrlen:是结构体sockaddr_in的长度。
返回值:成功返回0,否则返回-1.
7. send(int s, const void *msg,int len, unsigned int flags)/sendto(int s, const void *msg, int len, unsignedint flags, const struct sockaddr *to, int tolen),recv(int s, void*buf, int len, unsigned iint flags)/recvfrom(int s, void *buf, int len,unsigned int flags, struct sockaddr *from, int *fromlen):用Socket发送和接收数据。在连接建立完成后,通信双方就可以使用以上这些函数来进行数据的发送和接收操作。其中,send和recv用于连接建立以后的发送和接收。sendto和recvfrom用于非连接的协议。对于非non_blocking型的Socket,send将等待数据发送完后才返回;对于non_blocking型的Socket,send将立即返回,用户程序需要用select()函数决定网络发送是否结束。类似地,对于非non_blocking型的Socket,若系统没有收到任何数据,recv将等待接收数据到达后才返回;对于non_blocking型的Socket,recv将立即返回,并返回错误信息或接收到的数据字节数。sendto和recvfrom因为是非连接型的发送和接收,必须在参数中给出目的地址或者存放源地址的空间。
s参数:Socket描述符。
msg,buf参数:存放接收或者发送数据的存储空间。
len参数:接收或者发送数据的字节数。
to,from参数:sendto和recvfrom所使用的,目的方地址和存放源地址的空间。
tolen,fromlen参数:目的地址和源地址空间大小。
flag参数:通常设为0.
返回值:send/sendto返回实际发送的数据字节数,或者-1,表示出错。recv/recvfrom返回实际接收到的数据字节数,或者-1,表示出错。
8. read(int fd, void *buf, size_tcount)/write(int fd, const void *buf, size_t count):用系统文件操作进行Socket通信。在连接建立完成后,对于连接建立过程中被动的一方,在accept()正常返回后,它返回一个新的Socket,并且为该Socket分配了一个文件描述符;对于连接请求发起方,connect()正常返回后,相应的Socket中也包含有已分配的文件描述符。因此,可以使用标准的Unix文件读写函数read()/write()来进行Socket通信。要注意的是,由于网络数据和磁盘文件不一样,不是已经准备好的,因此,每次读写操作不一定能传送完指定长度的数据,需要由程序反复进行剩余部分的传送。另外,文件描述符是较底层的文件操作函数,不同于C语言中常用的FILE*。FILE*是使用fread/fwrite函数来进行读写操作的。
fd参数:文件或者Socket描述符。
buf参数:数据缓冲区。
count参数:数据字节数。
函数返回值:正常时,返回所读写的字节数(注意,可能小于count参数指定的数目);否则,返回-1.
9. getsockopt(int s, int level,int optname, void *optval, int *optlen)/setsockopt(int s, int level, intoptname, const void *optval, int optlen):获取、设置Socket特征选项。
常用的几个转换函数:(1)、inet_addr:将IP地址从点数格式转换成无符号长整型,它返回的地址是网络字节格式;(2)、inet_ntoa:将一个in_addr结构体输出成点数格式;(3)、htonl:将32位的主机字节顺序转化为32位的网络字节顺序;(4)、htons:将16位的主机字节顺序转化为16位的网络字节顺序;(5)、ntohs:将一个无符号短整形数从网络字节顺序转化为主机字节顺序;(6)、ntohl:将一个无符号长整形数从网络主机顺序转化为主机字节顺序。
以下是测试用例:
1. test_client1.cpp:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <iostream>#define PORT 7000int main()
{struct sockaddr_in server;int s, ns;int pktlen, buflen;char buf1[256], buf2[256];s = socket(AF_INET, SOCK_STREAM, 0);server.sin_family = AF_INET;server.sin_port = htons(PORT);server.sin_addr.s_addr = htons(INADDR_ANY);if (connect(s, (struct sockaddr*)&server, sizeof(server)) < 0) {perror("connect()");return -1;}for (;;) {printf("Enter a line: ");std::cin>>buf1;buflen = strlen(buf1);if (buflen == 1)break;send(s, buf1, buflen+1, 0);recv(s, buf2, sizeof(buf2), 0);printf("Received line: %s\n", buf2);}close(s);return 0;
}
2. test_server1.cpp:
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>#define PORT 7000int main()
{struct sockaddr_in client, server;int s, ns, pktlen;char buf[256];s = socket(AF_INET, SOCK_STREAM, 0);memset((char*)&server, sizeof(server), 0);server.sin_family = AF_INET;server.sin_port = htons(PORT);server.sin_addr.s_addr = htons(INADDR_ANY);bind(s, (struct sockaddr*)&server, sizeof(server));listen(s, 1);socklen_t namelen = sizeof(client);ns = accept(s, (struct sockaddr*)&client, &namelen);for (;;) {pktlen = recv(ns, buf, sizeof(buf), 0);if (pktlen == 0)break;printf("Received line:%s\n", buf);for (int i = 0; i < strlen(buf); i++)buf[i] = toupper(buf[i]);send(ns, buf, pktlen, 0);}close(ns);close(s);return 0;
}
执行说明:(1)、打开终端,分别执行:$ g++ -o server server.cpp , $ g++ -o client client.cpp ; (2)、打开终端,先执行服务器端程序:$ ./server ;再打开另一终端,执行客户端程序:$ ./client ;(3)、程序功能:服务器端接收从客户端来的数据,并将其接收的数据小写字母改为大写再发送给客户端,在客户端显示接收后的结果数据。当输入一个字符长度时退出。
注:以上部分内容整理自网络。
GitHub:https://github.com//fengbingchun/Linux_Code_Test
相关文章:

免费公开课 | 基于定制数据流技术的AI计算加速
随着人工智能时代的来临,业内对于更高效率算力的需求也越来越紧迫,而传统的 CPU 计算能力弱,只适合软件编程,并不适合应用于人工神经网络算法的自主迭代运算。为了满足支撑深度学习的大规模并行计算的需求,人工智能芯片…
代替国足踢决赛?马宁当选卡日大战第四官员
卡塔尔杀进亚洲杯决赛。 图片来源:Osports全体育图片社 中新网1月30日电 日本与卡塔尔将会师本届亚洲杯的决赛。北京时间30日,亚足联官方已经公布了本次决赛的裁判组,中国裁判员马宁将担任第四官员。 来自乌兹别克斯坦的亚洲金哨伊尔马托夫将…

AI规模化落地,英特尔至强的七重助力
当今时代,各行各业与人工智能(AI)加速融合,通过智能化创新来寻求业务转型升级。与为数不多的顶级AI研发公司相比,大多数传统行业或企业有着更丰富的 AI 应用场景,推动着规模化的AI应用落地,其AI…

Linux进程编程基础介绍
Linux系统是一个多进程的系统,它的进程之间具有并行性、互不干扰等特点。也就是说,每个进程都是一个独立的运行单位,拥有各自的权利和责任。其中,各个进程都运行在独立的虚拟地址空间,因此,即使一个进程发生…

关于互联网技术基层绩效管理的一些思考
起因是一篇内部的文章,那记录也就留在内部吧,磨炼了的价值观在自己心里就好。 类似的还有 1. 罗振宇不发年终奖:https://xueqiu.com/7118120763/119669075 2. 有赞白鸦强行一波996:https://baijiahao.baidu.com/s?id1623959680…

波纹管 编织管
为什么80%的码农都做不了架构师?>>> 波纹管 编织管 http://wenku.baidu.com/view/4272a9feaef8941ea76e057e.html 转载于:https://my.oschina.net/tadcat/blog/151049

Git基础(常用命令)介绍
版本控制是一种记录若干文件内容变化,以便将来查阅特定版本修订情况的系统. 关于版本控制分为三种:本地版本控制系统,如rcs;集中化的版本控制系统,如CVS、SVN;分布式版本控制系统,如Git。 Git基础要点 G…

MIT开发新加密货币,用户所需数据比比特币减少99%
MIT的研究人员开发了一种新的加密货币,大大减少了用户加入网络和验证交易所需的数据,与当今流行的加密货币相比,最高可达99%。这意味着网络更具扩展性。 像比特币之类流行的加密货币都是构建于区块链上的网络,而区块链是按照一系列…

深入了解AI加速芯片的定制数据流架构与编译器 | 公开课
随着人工智能时代的来临,业内对于更高效率算力的需求也越来越紧迫,而传统的 CPU 计算能力弱,只适合软件编程,并不适合应用于人工神经网络算法的自主迭代运算。为了满足支撑深度学习的大规模并行计算的需求,人工智能芯片…

《GPU高性能编程CUDA实战》中代码整理
CUDA架构专门为GPU计算设计了一种全新的模块,目的是减轻早期GPU计算中存在的一些限制,而正是这些限制使得之前的GPU在通用计算中没有得到广泛的应用。使用CUDA C来编写代码的前提条件包括:(1)、支持CUDA的图形处理器,即由NVIDIA推…

50年来最具影响力的十大编程语言!
作者 | javinpaul译者 | 馨怡责编 | 屠敏出品 | CSDN(ID:CSDNnews)【导语】“适者生存”的自然法则在应用竞争激烈的编程语言界同样适用,而在数百种编程语言中,相对而言,哪些最具影响力?哪些才是…

【基础篇】DatePickerDialog日期控件的基本使用(一)
项目步骤: 1.首先在Main.xml布局文件中添加一个Button标签,用来点击显示日期控件,Main.xml内容如下: <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android" xmlns:tools"http://sch…

PoPo数据可视化第9期
PoPo数据可视化 聚焦于Web数据可视化与可视化交互领域,发现可视化领域有意思的内容。不想错过可视化领域的精彩内容, 就快快关注吧 :)2018 in the Ito Design Lab(视频内容请关注微信公众号浏览)1900~2018年城市温度异常变化可视化Temperatur…

面向可解释的NLP:北大、哈工大等提出文本分类的生成性解释框架
作者 | Hui Liu, Qingyu Yin, William Yang Wang 译者 | Rachel编辑 | Jane出品 | AI科技大本营(ID: rgznai100)【导语】北大、哈工大和加州大学圣巴巴拉分校在 ACL 2019 的一篇论文中联合提出了一个全新的生成性解释框架,该框架能够对分类策…

pyramid参数
2019独角兽企业重金招聘Python工程师标准>>> 普通参数permission: 该view的访问权限,这个后续会具体介绍。attr: Pyramid默认调用的是view类的__call__函数,如果需要指定调用其他方法,通过attr指定。如attrindex。renderer: 指定构…

Linux下常用的C/C++开源Socket库
1. Linux Socket Programming In C : http://tldp.org/LDP/LG/issue74/tougher.html 2. ACE: http://www.cs.wustl.edu/~schmidt/ACE.html ACE采用ACE_OS适配层屏蔽各种不同的、复杂繁琐的操作系统API。 ACE是一个大型的中间件产品,代码20万行左右&…

前端技术选型的遗憾和经验教训
我是Max,Spectrum的技术联合创始人。Spectrum 是一个面向大型在线社区的开源聊天应用程序,最近被GitHub收购。我们是一个三人团队,主要拥有前端和设计背景,我们在这个项目上工作了近两年时间。 事后看来,以下是我做出的…

时间序列的建模新思路:清华、李飞飞团队等提出强记忆力E3D-LSTM网络
作者 | Yunbo Wang,、Lu Jiang、 Ming-Hsuan Yang、Li-Jia Li、Mingsheng Long、Li Fei-Fei译者 | 凯隐编辑 | Jane出品 | AI科技大本营(ID:rgznai100)【导读】如何对时间序列进行时空建模及特征抽取,是RGB视频预测分类࿰…

了解node.js
转载自http://debuggable.com/posts/understanding-node-js:4bd98440-45e4-4a9a-8ef7-0f7ecbdd56cb 当我向人们介绍node.js时,通常会得到两种反应,一种人马上就能了解,另一种则是非常困惑。 如果你是第二种人,请看一下我对node的解…

VS2013中Image Watch插件的使用(OpenCV)
之前在vs2010中写OpenCV程序时经常用NativeViewer,安装此插件后,在调试代码时,对于cv::Mat变量,CV_TYPE类型为CV_8UC1或CV_8UC3,可以随时查看显示结果。其操作步骤为:1. 从http://sourceforge.net/p…
【spring boot2】第8篇:spring boot 中的 servlet 容器及如何使用war包部署
嵌入式 servlet 容器 在 spring boot 之前的web开发,我们都是把我们的应用部署到 Tomcat 等servelt容器,这些容器一般都会在我们的应用服务器上安装好环境,但是 spring boot 中并不需要外部应用服务器安装这些servlet容器,spring …

让织梦内容页arclist标签的当前文章标题加亮显示
很多人在用织梦做站的时候,会用到在当前栏目页面,给当前栏目标题使用指定样式如标题加亮,或者放个背景图。这是一个很常用和实用的功能,比如在导航页面,标识当前在浏览哪个栏目。如下图: 但是有些时候&…

RHEL6入门系列之九,常用命令2
今天还是继续来学习Linux的基本命令。4、touch命令——建立空文件touch命令用于建立空文件。[rootlocalhost ~]# mkdir /root/test ‘创建目录/root/test[rootlocalhost ~]# touch /root/test/test1.txt ‘在目录/root/test中创建空文件test1.txt[rootlocalhos…

为什么华为200万招聘AI博士,马斯克却推出脑机接口对抗AI?
作者 | 伍杏玲来源 | CSDN(ID:CSDNnews)7 月,华为一则薪资通知刷爆朋友圈:华为给8位博士应届生给予 89.6 万至 201 万的年薪。其中薪资最高的两位博士均研究人工智能相关专业。7 月还有一件大事:马斯克发布…

Artistic Style在windows下的使用(C/C++)
ArtisticStyle是一个开源的源代码格式化工具。主页地址为:http://astyle.sourceforge.net/,它可以应用在C、C、Objective-C、C#、Java等程序语言中。http://astyle.sourceforge.net/astyle.html中为对使用它的详细介绍。从http://sourceforge.net/projec…

ESXi主机与网络中其他主机的网咯数据包捕获
1、tcpdump-uw -i vmk0 -s 1514 host x.x.x.x 指定捕获与某台主机间的网络数据包2、tcpdump -i vmk0 -s 1514 port not 22 and port not 53 在捕获的数据包中,过滤掉指定端口的数据包3、tcpdump-uw -i vmk0 -s 1514 -w traffic.pcap 捕获的数据包保存成PCAP文件&…

Windows下批处理文件(.bat)的使用
批处理(Batch),就是进行批量的处理,英文译文BATCH,批处理文件后缀BAT就取的前三个字母,通常被认为是一种简化的脚本语言,它应用于DOS和Windows系统中。批处理文件是扩展名为.bat或.cmd的文本文件,包含一条或…

金融业加速智能化,解析360金融AI基础架构和应用
传统金融信贷业务中,催收、客服及电销人员占比超过 60%,人员素质参差不齐的现状造成了管理成本过高的问题,由此衍生的客户体验差,也成为困扰金融业的一大通病。 8 月 15 日,在 360金融 AI 媒体开放日上,360…

正则:匹配一个汉字姓名
//汉字姓名正则var reg/^[\u4e00-\u9fa5]{2,}(\.[\u4e00-\u9fa5])?$/console.log(reg.test(张卫健.爱新觉罗))console.log(reg.test(兔子)) 复制代码

NLP命名实体识别开源实战教程 | 深度应用
作者 | 小宋是呢来源 | CSDN博客近几年来,基于神经网络的深度学习方法在计算机视觉、语音识别等领域取得了巨大成功,另外在自然语言处理领域也取得了不少进展。在NLP的关键性基础任务—命名实体识别(Named Entity Recognition,NER…