关键词不能为空

当前您在: 主页 > 英语 >

socket()及相关函数介绍

作者:高考题库网
来源:https://www.bjmy2z.cn/gaokao
2021-02-15 21:15
tags:

-

2021年2月15日发(作者:lancy)


socket


函数介绍



函数原型


domain type protocol errno


示例



函数原型


socket()


函数的原型如下,


这个函数< /p>


建立一个协议族为


domain



协议类型为


type



协议编号为


protocol



套接 字文件描述符




如果函数调用成功, 会返回一个


标识这个套接字的文件描述符


,失败的时候返回


-1



#include



#include


int


socket(


int


domain,


int


type,


int


protocol);


1< /p>



domain



函数


socket()


参数


doma in


用于设置网络通信的域




1 domain


的值及含义



函数


socket()


根据这个参数选择通信协议的 族。通信协议族在文件


sys/socket.h


中定义。



名称



PF_UNIX,PF_LOCAL


AF_INET,PF_INET


PF_INET6


PF_IPX


PF_NETLINK


含义



本地通信



IPv4 Internet


协议



IPv6 Internet


协议



IPX- Novell


协议



内核用户界面设备



名称



PF_X25


PF_AX25


PF_ATMPVC


PF_APPLETALK


PF_PACKET


含义



ITU-T X25 / ISO-8208


协议



Amateur radio AX.25


原始


ATM PVC


访问



Appletalk


底层包访问



2



Type



函数


socket()


的参数


type


用于设置套接字通信的类型




2 type


的值及含义



主要有


SOCKET_STREAM


(流式套接字)、


SOCK


——


DGRAM


(数据包套接 字)等。



名称



含义



SOCK_STREAM


Tcp


连接,提供序列化的、可靠的、双向连接的字节流。支持带外 数据传输



SOCK_DGRAM


SOCK_SEQPAC


KET


SOCK_RAW


SOCK_RDM


SOCK_PACKET


支持


UDP


连接(无连接状态的消息)



序列化包 ,提供一个序列化的、可靠的、双向的基本连接的数据传输通道,


数据长度定常。每次调 用读系统调用时数据需要将全部数据读出



RAW


类型,提供原始网络协议访问



提供可靠的数据报文,不过可能数据会有乱序



这是一个专用类型,不能呢过在通用程序中使用






所有


的协



族都实




这些


协议



型,例




AF_INET



议族就




实现


SOCK_SEQPACKET


协 议类型。


protocol


函数


soc ket()


的第


3


个参数


protocol


用于制定


某个协议的特定类型,即


type


类型中的某个类


< p>


通常某协议中只有一种特定类型,这样


prot ocol


参数仅能设置为


0



但是有些协议有多种特定的类型,就需要设置这个参数来选


择特定的类型 。





EACCES


EAFNOSUPPORT


EINVAL


EMFILE


ENFILE


ENOBUFS/ENOMEM


其他



含义



没有权限建立制定的


domain


的< /p>


type



socket


不支持所给的地址类型



不支持此协议或者协议不可用



进程文件表溢出



已经达到系统允许打开的文件数量,打开文件过多


< p>
内存不足。


socket


只有到资源足够或者有进 程释放内存




EPROTONOSUPPORT


制定的协议


type



domain


中不 存在



类型为


SOCK_STREAM


的套接字表示一个双向的字节流,与管道类似。流式的套接字在


进行数据收发之前必须已经连接,


连接使用


connect()


函数进行。


一旦连接,


可以使用


read()


或者


write()

< p>
函数进行数据的传输。流式通信方式保证数据不会丢失或者重复接收,当数据


在一段时间内任然没有接受完毕,可以将这个连接人为已经死掉。


< br>SOCK_DGRAM



SOCK_RAW

< p>
这个两种套接字可以使用函数


sendto()


来 发送数据



使


1




recvfrom()

< p>
函数接受数据,


recvfrom()


接受来自制 定


IP


地址的发送方的数据。



SOCK_PACKET


是一种专用的数据包,它直接从设备驱动接受 数据。



errno


函数


socket()


并不总是执行成功,


有可能会出现 错误,


错误的产生有多种原因,


可以


通 过


errno


获得:





3 errno


的值及含义



示例




建立一个流式套接字:



int sock = socket(AF_INET, SOCK_STREAM, 0);


看一下


socket


函数的原型:


S OCKET PASCAL FAR socket (int af, int type, int protocol);


典型的调用方式为:


unsigned int sockSrv = socket(AF_INET, SOCK_STREAM, 0);




address family


的缩写,实际上就是指明域


domain,


这个


af


主要是用来区分是创建

< p>
ipv4


的套接字还是


ipv6

< br>的套接字。




当然,



顺便说一下,



如果是在


unix


中,



第一个参


数还可以是


AF_UNIX,


表示这个


socket


既不是


ipv4



socket,

< br>也不是


ipv6



socket ,



是非网络形式的


unix



socket,


可以用来进行非网络形式的进程间通信。



在很多嵌入式系


统中,



进程间的通信均是通过非网络形式的


unix


域套接 字来完成的。


不过,



我们要明白,



unix


域套接字的客户端和服务端进行通信时,



客户端和服务端必须位于同一台机器上,




且效率比网络套接字更高。



2.


我以前总是以为,


< p>
这个


type


值决定了是


tcp


套接字还是


udp


套接字,



其实不是的。



type


值决定的是流套接字还是数据报套接字或者其他。


< /p>


注意流套接字不一定是


tcp




数据报套


接字也不一定是


udp.


3. protocol


这个值通常为


0,



0


的时候是什么意思呢?



意思是,



如果


type


是流套接字,




protocol



0




那么就是就是默认的流套接字


-- -tcp


套接字。



同理,



如果


type


是数据


报套接字,




protocol



0,


那么就是默认的数据报套接字


---udp


套接字。



返回值其实就是一个无符号整形,


用于标识和索引套接字。


可以通过返回值判断套接字是否


创建成功。



sockaddr_in

< p>


sin_zero


的意义,以及


sockaddr_in sockaddr in_addr


区别联系



转自:


/blog/static/88881620289/


struct sockaddr {unsigned short sa_family; // address family, AF_xxx


char sa_data[14];


// 14 bytes of protocol address};


sa_family


是地址家族,


“AF_xxx”



常设为


“AF_INET”


< br>代表


Internet



TCP /IP



地址族。


< br>sa_data


是协议地址,由


sa_family


决定。若


sa_family=AF_INET

,则


sa_data



socka ddr_in



sin_addr


和< /p>


sin_port



换句话说这时


sockaddr


可当作


sockaddr_ in


看。



struct sockaddr_in {


short int sin_family; // Address family


unsigned short int sin_port; // Port number


struct in_addr sin_addr; // Internet address


unsigned char sin_zero[8]; // Same size as struct sockaddr


};


struct in_addr {unsigned long s_addr; // t


hat’s a 32


-bit long, or 4 bytes};[::


备注


1]


si n_family


意义与


sa_family

< br>同。



sin_port


存储端 口号(使用网络字节顺序)



sin_addr


存储


IP


地址,使用


in_a ddr


这个数据结构



sin_zer o


是为了让


sockaddr



sockaddr_in


两个数据结构保持大小相同而保留的空字节。





in_ addr


结构体中,


s_addr


按照 网络字节顺序存储


IP


地址。



sin_zero


用来将


sockaddr_ in


结构填充到与


struct sockaddr

< p>
同样的长度,可以用


bzero()


< p>
2



memset()


函数将其置为零。


指向


sockaddr_in


的指针和指向


sockaddr


的指针可以相互转换,


这意味着如果一个函数所需参数类型是


sockaddr


类型时,你可以在函数调用的时候将一个


指向


sockaddr_in


的指针转换为指向


sockaddr< /p>


的指针;或者相反。



想来你是要进行网络编程,使用


socket, listen, bind


等函数。你只要记住,填值的时候使用


sockaddr_in


结构,而作为函数的参数传入的时候转换成

< br>sockaddr


结构就行了,毕竟都是


16

< p>
个字符长。




[::


备注


1]

/*


实际上在


Winsock2.h


中查看


in_addr*/


struct in_addr {



union {



struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;



struct { u_short s_w1,s_w2; } S_un_w;



u_long S_addr;



} S_un;


#define s_addr


S_un.S_addr /* can be used for most tcp & ip code */


#define s_host


S_un.S_un_b.s_b2/* host on imp */


#define s_net


S_un.S_un_b.s_b1/* network */


#define s_imp


S_un.S_un_w.s_w2 /* imp */


#define s_impno S_un.S_un_b.s_b4 /* imp # */


#define s_lh


S_un.S_un_b.s_b3/* logical host */


};


socket


编程


——


sockaddr_in


结构体操作

< p>


sockaddr


结构体




sockaddr


的缺陷:


sa_data


把目标地址和端口信息混在一起了



struct sockaddr {


unsigned short sa_family;char sa_data[14]; };


sa_family


是通信类型,最常用的值是




sa_data14


字节,包含套接字中的目标地址和端口信息



sockaddr_in


结构体


< /p>


sockaddr_in


结构体解决了


s ockaddr


的缺陷,把


port



addr


分开储存在两个变量中



struct sockaddr_in {





short int sin_family;





unsigned short int sin_port;


struct in_addr sin_addr;


struct in_addr { unsigned long s_addr; }


unsigned char sin_zero[8];


}


sin_por t



sin_addr


都必须是


NBO


一般可视化的数字都是


HBO


(本机字节顺序)


sin_zero


初始值应该使用函数



bzero()



全部置零。




一般采用下面语句



struct sockaddr_in cliaddr;


bzero(&cliaddr,sizeof(cliaddr));


sockaddr_in


结构体变量的基本配置



3



struct sockaddr_in ina;


bzero(&ina,sizeof(ina));


_family=AF_INET;


_port=htons(23);


_addr.s_addr = inet_addr(


sockaddr




sockaddr_in


的相互关系



一般先把


sockaddr_in


变量 赋值后,强制类型转换后传入用


sockaddr


做参数的函数



sockaddr_in


用于


socket


定义和赋值



sockaddr


用于函数参数



最典型的源、目的节点


socket


定义< /p>



对于源、目的地址和源、目的地址端口,需要建立两个


socket


变量



cliaddr


绑定源地址和源端口



servaddr


用于


connect



sendto


的设定目的地址和目的 端口



struct sockaddr_in servaddr,cliaddr;


create_socket(char *server_addr_string,unsigned int server_port)


{



socket

< br>赋值



bzero(&cliaddr,sizeof(cliaddr));


_family = AF_INET;



通常


TCP/UDP


协议源地址和端口都是随机的



_addr.s_addr = htons(INADDR_ANY);


_port = htons(0);


目的


socket


赋值



bzero(&servaddr,sizeof(servaddr));


_family = AF_INET;


inet_aton(server_addr_string,&_addr);


_port = htons(server_port);


}


网络字节顺序



(Network


Byte


Order)


NBO


,结构体的


sin_port



sin_addr


都必须是


NBO


本机字节顺序



(Host Byte Order) HBO


一般可视化的数字都是


HBO NBO



HBO


二者转换



inet_addr()


将字符串点数格 式地址转化成无符号长整型



unsigned long s_addr s_addr;




inet_aton()


将字符串点数格式地址转化成


NBO


inet_ntoa ()




NBO


地址转化成字符串点数格式



htons()


htonl()


ntohs()


ntohl()


常用的是


htons(),inet_addr()


正好对应结构体的端口类型和地址类型



三种给


socket


赋值地址的方法



inet_aton(server_addr_string,&_addr);


_addr.s_addr = inet_addr(




INADD R_ANY


转不转


NBO


随便



4



_addr.s_addr = htons(INADDR_ANY);


_addr.s_addr = INADDR_ANY;


两种给


socket


赋值端口的方法



#define MYPORT 3490


_port = htons(MYPORT);


0


(随机端口)转不转


NBO


随便



_port = htons(0);


_port = 0;


htons/l

< br>和


ntohs/l


等数字转换都不能用于地址转换,


因为地址都是点数格式,


所以地址只


能采用 数字


/


字符串转换如


inet_ato n,inet_ntoa;


唯一可以用于地址转换的


hton s


是针对


INADDR_ANY


_addr.s_addr = htons(INADDR_ANY)


inet_a ddr()



inet_aton()


的区别



inet_addr()


是返回值型



struct sockaddr_in ina;


_addr.s_addr = inet_addr(


inet_aton()


是参数指针型



struct sockaddr_in ina;


inet_aton(


inet_ntoa



NBO


地址 转化成字符串点数格式



参数:结构体变量


.sinaddr


返回值:字符串指针



a1 = inet_ntoa(_addr);


printf(


address 1: 132.241.5.10


inet_addr()


的缺陷 :


必须对


-1


做检测处理,

< p>


inet_addr()


的结果是整型,


发生错误时返回


-1






_addr.s_addr< /p>



unsigned


long


型。


1



long < /p>


short


显示成


111111111,



IP


地址


2 55.255.255.255


相符合!会被误认为广播地址!



SOCKADDR_IN


结构体的作用是:定义



地方



,宣誓主权




前面我们已经说了


,


套接字也创建了,




地方



也定义了,下面就需要将


socket


放置在这个



地方


”(TCP)


,将他们紧紧地捆绑在一起,用


bind


函数吧


,


我们来看看函数原型:



int PASCAL FAR bind (SOCKET s, const struct sockaddr FAR *addr, int namelen);


第一个参数当然是待绑定的套接字啦,第二个参数是标识绑定在哪个



地方





第三个参


数是这个



地方



的占地大小。




返回值表示绑定操作是否成功,


0


表示 成功,



-1


表示不成功。函数的返回 值千万不要


忽视,上次就被人说了。



一般是这么调用的:



iRet = bind(sockSrv,(SOCKADDR*)&addrSrv, sizeof(SOCKADDR)); //


注意强制转换



我们来对比一下文件


I/O


操作和网络


I/O


操作:



打开一个文件后,



便可以对文件进行读写


操作了,



但是,



网络


I/O


实际上有三个步骤来完成这个功能:



1.


打开


/


创建


socket


2.


命名


socket,



我们知道,



socket

< p>
名称包含



协议,



ip


地址


,



端口号



这三个要素,

< br>



5


-


-


-


-


-


-


-


-



本文更新与2021-02-15 21:15,由作者提供,不代表本网站立场,转载请注明出处:https://www.bjmy2z.cn/gaokao/656267.html

socket()及相关函数介绍的相关文章