linux socket api

socket接口是TCP/IP网络的API,socket接口定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序。要学Internet上的TCP/IP网络编程,必须理解socket接口。
socket接口设计者最先是将接口放在Unix操作系统里面的。如果了解Unix系统的输入和输出的话,就很容易了解socket了。网络的 socket数据传输是一种特殊的I/O,socket也是一种文件描述符。socket也具有一个类似于打开文件的函数调用socket(),该函数返回一个整型的socket描述符,随后的连接建立、数据传输等操作都是通过该socket实现的。常用的socket类型有两种:流式socket (SOCK_STREAM)和数据报式socket(SOCK_DGRAM)。流式是一种面向连接的socket,针对于面向连接的TCP服务应用;数据报式socket是一种无连接的socket,对应于无连接的UDP服务应用。
socket建立
为了建立socket,程序可以调用socket函数,该函数返回一个类似于文件描述符的句柄。socket函数原型为:
int socket(int domain, int type, int protocol); domain指明所使用的协议族,通常为PF_INET,表示互联网协议族(TCP/IP协议族);type参数指定socket的类型: SOCK_STREAM 或SOCK_DGRAM,socket接口还定义了原始socket(SOCK_RAW),允许程序使用低层协议;protocol通常赋值 "0"。 socket()调用返回一个整型socket描述符,你可以在后面的调用使用它。
socket描述符是一个指向内部数据结构的指针,它指向描述符表入口。调用socket函数时,socket执行体将建立一个socket,实际上 "建立一个socket"意味着为一个socket数据结构分配存储空间。socket执行体为你管理描述符表。 两个网络程序之间的一个网络连接包括五种信息:通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。socket数据结构中包含这五种信息。
socket配置
通过socket调用返回一个socket描述符后,在使用socket进行网络传输以前,必须配置该socket。面向连接的socket客户端通过调用connect函数在socket数据结构中保存本地和远端信息。无连接socket的客户端和服务端以及面向连接socket的服务端通过调用 bind函数来配置本地信息。
bind函数将socket与本机上的一个端口相关联,随后你就可以在该端口监听服务请求。bind函数原型为:
int bind(int sockfd,struct sockaddr*my_addr, int addrlen); Sockfd是调用socket函数返回的socket描述符,my_addr是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;addrlen常被设置为sizeof(struct sockaddr)。
struct sockaddr结构类型是用来保存socket信息的:
struct sockaddr {
unsigned short sa_family; /*地址族,AF_xxx*/ char sa_data[14]; /*14字节的协议地址*/ };
sa_family一般为AF_INET,代表Internet(TCP/IP)地址族;sa_data则包含该socket的IP地址和端口号。 另外还有一种结构类型: struct sockaddr_in {
short int sin_family; /*地址族*/
unsigned short int sin_port; /*端口号*/ struct in_addr sin_addr; /*IP地址*/
unsigned char sin_zero[8];/*填0保持与sockaddr同样大小*/ };
这个结构更方便使用。sin_zero用来将sockaddr_in结构填充到与struct sockaddr同样的长度,可以用bzero()或memset()函数将其置为零。指向
sockaddr_in 的指针和指向sockaddr的指针可以相互转换,这意味着如果一个函数所需参数类型是sockaddr时,你可以在函数调用的时候将一个指向 sockaddr_in的指针转换为指向sockaddr的指针;或者相反。 使用bind函数时,可以用下面的赋值实现自动获得本机IP地址和随机获取一个没有被占用的端口号:

my_addr.sin_port=0; /* 系统随机选择一个未被使用的端口号*/ my_addr.sin_addr.s_addr=INADDR_ANY; /* 填入本机IP地址*/

通过将my_addr.sin_port置为0,函数会自动为你选择一个未占用的端口来使用。同样,通过将my_addr.sin_addr.s_addr置为INADDR_ANY,系统会自动填入本机IP地址。
注意在使用bind函数是需要将sin_port和sin_addr转换成为网络字节优先顺序;而sin_addr则不需要转换。
计算机数据存储有两种字节优先顺序:高位字节优先和低位字节优先。Internet上数据以高位字节优先顺序在网络上传输,所以对于在内部是以低位字节优先方式存储数据的机器,在Internet上传输数据时就需要进行转换,否则就会出现数据不一致。
htonl():把32位值从主机字节序转换成网络字节序 htons():把16位值从主机字节序转换成网络字节序 ntohl():把32位值从网络字节序转换成主机字节序 ntohs():把16位值从网络字节序转换成主机字节序
bind()函数在成功被调用时返回0;出现错误时返回 "-1"并将errno置为相应的错误号。需要注意的是,在调用bind函数时一般不要将端口号置为小于1024的值,因为1到1024是保留端口号,你可以选择大于1024中的任何一个没有被占用的端口号。
连接建立
面向连接的客户程序使用connect函数来配置socket并与远端服务器建立一个TCP连接,其函数原型为:
int connect(int sockfd, struct sockaddr*serv_addr,int addrlen); Sockfd 是socket函数返回的socket描述符;serv_addr是包含远端主机IP地址和端口号的指针;addrlen是远端地质结构的长度。 connect函数在出现错误时返回-1,并且设置errno为相应的错误码。
进行客户端程序设计无须调用bind(),因为这种情况下只需知道目的机器的IP地址,而客户通过哪个端口与服务器建立连接并不需要关心,socket执行体为你的程序自动选择一个未被占用的端口,并通知你的程序数据什么时候到达端口。
connect函数启动和远端主机的直接连接。只有面向连接的客户程序使用socket时才需要将此socket与远端主机相连。无连接协议从不建立直接连接。面向连接的服务器也从不启动一个连接,它只是被动的在协议端口监听客户的请求。
listen函数使socket处于被动的监听模式,并为该socket建立一个输入数据队列,将到达的服务请求保存在此队列中,直到程序处理它们。 int listen(int sockfd, int backlog);
Sockfd 是socket系统调用返回的socket 描述符;backlog指定在请求队列中允许的最大请求数,进入的连接请求将在队列中等待accept()它们(参考下文)。Backlog对队列中等待服务的请求的数目进行了限制,大多数系统缺省值为20。如果一个服务请求到来时,输入队列已满,该socket将拒绝连接请求,客户将收到一个出错信息。
当出现错误时listen函数返回-1,并置相应的errno错误码。
accept()函数让服务器接收客户的连接请求。在建立好输入队列后,服务器就调用accept函数,然后睡眠并等待客户的连接请求。 int accept(int sockfd, void*addr, int*addrlen);
sockfd是被监听的socket描述符,addr通常是一个指向sockaddr_in变量的指针,该变量用来存放提出连接请求服务的主机的信息(某台主机从某个端口发出该请求);addrten通常为一个指向值为sizeof(struct sockaddr_in)的整型指针变量。出现错误时accept函数返回-1并置相应的errno值。 首先,当accept函数监视的 socket收到连接请求时,socket执行体将建立一个新的socket,执行体将这个新socket和请求连接进程的地址联系起来,收到服务请求的初始socket仍可以继续在以前的 socket上监听,同时可以在新的socket描述符上进行数据传输操作。 数据传输
send()和recv()这两个函数用于面向连接的socket上进行数据传输。 int send(int sockfd, const void*msg, int len, int flags);
Sockfd是你想用来传输数据的socket描述符;msg是一个指向要发送数据的指针;Len是以字节为单位的数据的长度;flags一般情况下置为0(关于该参数的用法可参照man手册)。
send()函数返回实际上发送出的字节数,可能会少于你希望发送的数据。在程序中应该将send()的返回值与欲发送的字节数进行比较。当send()返回值与len不匹配时,应该对这种情况进行处理。
int recv(int sockfd,void*buf,int len,unsigned int flags);基于Linux的SOCKET编程。
喜欢阅读
  • 婚情难隐:薄先生请走开

    婚情难隐:薄先生请走开

    三年前,她被深爱的男人狠狠践踏,让她大着肚子独自一人走完婚礼。三年后,她脱胎换骨、美丽不可方物地出现,笑着说:“老公是什么?我不需要老公。”身后的男人目光一沉,薄唇抿成了两片冰冷的刀刃:“秦烟,你再说一遍试试?”

  • 女律师的贴身保镖

    女律师的贴身保镖

    昔日战争之王,如今落魄入世。待张阳寻到儿时玩伴,画风却是不一样了。“还记得当年大明湖畔的夏。。。”

  • 大唐败家驸马爷

    大唐败家驸马爷

    看着大唐贞观年的街道,刚穿越过来的林玉生无可恋。作为大人们口中,别人家的孩子,没办法,只能靠自己了。

  • 女总裁的修仙高手

    女总裁的修仙高手

    渡劫失败的苏浩身怀修仙界至高法门重回都市,这一世,绝不让悲剧重演。

  • 暗夜狂尊

    暗夜狂尊

    茫茫深山中的纨绔弟子进入大都市,小山民变为小市民,情道,黑道,商道,官道,畅通无阻。一个小市民的逆天史!

  • 甜妻归来:莫少别来无恙

    甜妻归来:莫少别来无恙

    你的出现,照亮了我整个心脏,许诺只是一个被莫家收养的孤女,一腔真心也只为一个人跳动过,莫承,用他的行动告诉所有人,他爱许诺,是透进血肉,深入骨髓的那种。

  • 欺心影后

    欺心影后

    情路相逢娇妻胜,初次交锋,他霸占了她的人,她夺走了他的心。再次相遇,秦大总裁只能选择跪着键盘唱《征服》,只求老婆能多看他一眼。老婆篇:秦大总裁:“老婆我现在不稀罕商业龙头称号了,正准备征服传媒界。”某媱:“哦,意义在何?”秦大总裁一脸滑稽笑容,道:“这样全世界的绯闻八卦都可以被咱俩承包了。”某媱:“老实交代,想和哪个嫩模,哪个明星传绯闻?”秦大总裁扑身而上,道:“当然是我老婆~”情敌篇:秦大总裁:“这些钱够你吃一辈子余记蟹黄包,拿着钱离开我老婆。”某情敌:“不要,媱媱买的蟹黄包最好吃。”秦大总裁:“为什么?”某情敌:“因为媱媱说她买给我的蟹黄包里带着她对我的爱。”秦大总裁脸上笑嘻嘻,内心MMP!包子篇:秦大总裁:“今晚去睡自己的床。”包子满脸委屈:“我还小。。。”秦大总裁:“秦皬泽,你已经是六岁的大人了,不是三岁小孩儿了。”包子乖乖地转头回房,但觉得爹地的话怪怪的。。。。。。

  • 萌宝强袭:总裁老爸太傲娇

    萌宝强袭:总裁老爸太傲娇

    天才萌宝神助攻,渣男贱女挨个儿虐个遍。传闻,厉太太凶恶刁蛮,用两娃性命要挟才上位。厉北言怒火冲天,“胡说!我太太温柔贤惠、善解人意、宜室宜家,事事以我为先!”萌宝撇嘴,“粑粑,麻麻说搓衣板跪够一个小时才能起来哦~”厉北言,“…老婆我错了!”

  • 猜你喜欢
    热门推荐
  • 绝地求生大逃杀
  • xmind
  • 武神天下
  • 蚌埠天气
  • 常德天气
  • tplink无线路由器怎么设置
  • 掌上公交
  • k歌
  • 小三跳楼
  • 魔域官网
  • 无码电影
  • 动物图片
  • 清纯少女
  • 女生烫发发型图片
  • 狼纹身图案大全
  • 西红柿的营养价值
  • 手足口病治疗
  • 洪尧
  • All Right Reserved 知识库