TCP API 网络编程函数

  1. 1.WSAStartup()函数 
  2. WSAStartup():功能是加载ws2_32.dll等socket程序运行环境的动态库(DLL)。在程序初始化后,socket程序运行所依赖的动态链接库不一定已经加载,WSAStartup保证了Socket动态链接库的加载。 
  3. int WSAStartup(_in Word wVersionRequested,_out LPWSDATA lpWSAData); 
  4. wVersionRequested:是Socket程序库的版本。高字节指定所需要库文件的副版本,低字节指定主版本。在程序中可以使用MAKEWORD(X,Y)方便指定参数,其中X是指高位字节,Y是指低位字节。一般使用MAKEWORD(2,2)宏 
  5. lpWSAData:输出参数,指向WSADATA结构的指针,用于返回scoket库初始化的信息 
  6. 返回值:0表示成功, 
  7. WSACleanup():与WSAStartup()的功能相反,WSACleanup释放ws2_32.dll库。 
  8. WSADATA wsaData;   
  9. LPVOID recvbuf;   
  10. if (WSAStartup(MAKEWORD(2,2),&wsaData) != NO_ERROR)   
  11. {   
  12. printf("Error at WSAStartup()\n");   
  13.  
  14. if(LOBYTE(wsaData.wVersion)!=2 || HIBYTE(wsaData.wVersion) != 2)//检查返回的DLL是否为2.2 
  15. { 
  16.       //没有找到可用的DLL 
  17.       WSACleanup(); 
  18.       return; 
  19. } 
  20.  
  21. 2.socket()函数 
  22. SOCKET socket( int af, int type, int protocol ); 等价于WSASocket() 
  23. 参数:int af:协议的地址家族(AF_UNIX,AF_INET等),AF_UNIX只能够用于单一的Unix系统进程间的通信,而AF_INET是针对Internet的,因此可以允许远程——本机之间的通信。AF:Address families(地址协议族)。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。创建TCP或者UDP套接字时,该参数为AF_INET 
  24. int type:协议的套接字类型:有SOCK_STREAM(TCP),SOCK_DGRAM(UDP),SOCK_RAM 3种 
  25. int protocol:指定协议(有IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议),由于我们指定了type,所以这个地方我们一般只要用0来代替就可以了 
  26. 返回值:若成功返回SOCKET对象标识,SOCKET就是unsigned int;如失败,则返回INVALID_SOCKET,调用WSAGetLastError()可得知原因,所有WinSocket的函数都可以使用这个函数来获取失败的原因。 
  27. 注意:并不是上面的type和protocol可以随意组合的,如SOCK_STREAM不可以跟IPPROTO_UDP组合。当protocol为0时,会自动选择type类型对应的默认协议。 
  28. 当我们调用socket创建一个socket时,返回的socket描述字它存在于协议族(address family,AF_XXX)空间中,但没有一个具体的地址。如果想要给它赋值一个地址,就必须调用bind()函数,否则就当调用connect()、listen()时系统会自动随机分配一个端口。 
  29.  
  30. 3.bind()函数 
  31. 当我们调用socket创建一个socket时,返回的socket描述字它存在于协议族(address family,AF_XXX)空间中,但没有一个具体的地址。如果想要给它赋值一个地址,就必须调用bind()函数,否则就当调用connect()、listen()时系统会自动随机分配一个端口。 
  32. bind()函数把一个地址族中的特定地址赋给socket。例如,对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket。 
  33. int bind(SOCKET s,sockaddr * name,int namelen); 
  34. 参 数: s:Socket对象名,它通过socket()创建了,唯一标识一个socket 
  35. name:地址,服务器地址信息名称(包含信息有:地址协议族,服务器本机的IP,要监听的端口) 
  36. namelen:sockaddr的结构长度 
  37. 返回值:成功返回0,否则返回SOCKET_ERROR 
  38. 通常服务器在启动的时候会绑定一个众说周知的地址(如ip地址+端口号),用于提供服务,客户就可以通过它(ip+port)来连接服务器;而客户端就不用指定,有系统自动分配一个端口号和自身的ip地址组合。这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不用调用,而是在connect()时由系统随机生成一个。 
  39. SOCKET s; 
  40. SOCKADDR_IN servAddr; 
  41. //定义服务器地址 
  42. servAddr.sin_family=AF_INET; 
  43. servAddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//如果程序不关心分配给它的地址,则可将地址设置为INADDR_ANY,可以使用任意网络接口。 
  44. servAddr.sin_port=htons(2222); 
  45. if (bind(s,(SOCKADDR*)&servAddr,sizeof(servAddr)) == SOCKET_ERROR)//绑定服务器地址 
  46.  
  47.   //绑定套接字失败 
  48. } 
  49.  
  50. 4.listen()函数 
  51. int listen(SOCKET s,int backlog);将套接字设置为监听模式 
  52. 参 数: s:一个已绑定的套接字 
  53. backlog:指定等待连接的最大队列长度(一般2~4,用SOMAXCONN则有系统确定)。socket可以排队的最大连接个数,不是最多可以连接几个客户端。更具体些:TCP模块允许的已完成三次握手过程(TCP模块完成)但还没来得及被应用程序accep()的最大连接数。eg:listen(socketID,3);如果有4个客户端同时向服务器发出请求,那么前3个连接会被放到等待处理的队列中,以便服务器依次为他们服务,而第4个连接将会造成WSAECONNREFUSED错误。当服务器接受了一个连接请求时,这个请求就从队列中删除。 
  54. 返回值:成功返回0,否则返回SOCKET_ERROR 
  55. socket()函数创建的socket默认是一个主动类型的,listen()函数则将主动连接套接口socket变为被动连接套接口,使得这个进程可以接受其他进程的请求(客户的连接请求),从而成为一个服务器进程。 
  56.  
  57. 5.accept()函数 
  58. SOCKET accept(SOCKET s,_output struct sockaddr * addr,_output int * addrlen); 
  59. 参数:s:监听套接字, 
  60. addr:存放来连接的客户端的地址和端口,(若客户端使用了bind()来绑定客户端本地的IP和Port,则服务器端会得到客户端bind的端口,而不是服务器端自动分配的端口)。当我们调用socket()创建一个socket时,返回的socket描述字它存在于协议族(address family,AF_XXX)空间中,但没有一个具体的地址。如果想要给它赋值一个地址,就必须调用bind()函数,否则就当调用connect()、listen()时系统会自动随机分配一个端口。若对客户端的IP地址不感兴趣,则可以设为NULL 
  61. addrlen:返回addr结构的长度,sizeof(SOCKADDR_IN),当addr为NULL时,addrlen则可以为NULL 
  62. 返回值:功返回一个新产生的Socket对象,否则返回INVALID_SOCKET 
  63. accept()默认会阻塞进程(所以需要一个单独的线程来等待客户端的连接),直到有一个客户连接建立后返回,它返回的是一个新可用的套接字,这个套接字就是连接套接字。 
  64. 监听套接字:监听套接字正如accept()的参数sockfd,它就是监听套接字,在调用listen()函数之后。 
  65. 连接套接字:一个套接字会从主动连接的套接字变为一个监听套接字;而accept()返回的是已连接socket描述字(一个连接套接字),它代表一个网络已经存在的点点连接。 
  66. 一个服务器通常仅仅只创建一个监听socket描述符,它在该服务器的生命周期内一直存在。内核为每个有服务器进程接收的客户端连接创建了一个已连接的socket描述符,当服务器完成了对某个客户的服务后,相应的已连接socket描述符就被关闭。 
  67. 连接套接字并没有占有新的端口与客户端通信,依然使用的是监听套接字一样的端口号。 
  68.  
  69. 6.recv()函数 
  70. int recv( SOCKET s, char FAR *buf, int len, int flags );等级与WSARecv() 
  71. 参数:s:Socket 的识别码 
  72. buf:接收数据缓冲区 
  73. len:缓冲区的长度 
  74. flags:该参数影响该函数的行为,可以设为 0(表示无特殊行为),MSG_PEEK(会使有用的数据被复制到接收缓冲区内,但没有从系统缓冲区中将其删除),MSG_OOB(表示处理带外数据) 
  75. 返回值:若成功则返回接收资料的长度,否则返回SOCKET_ERROR 
  76.  
  77. 7.send()函数 
  78. int send( SOCKET s, const char FAR *buf,int len, int flags );等价于WSASend() 
  79. 参数:s:Socket 的识别码 
  80. buf:存放要传送数据的暂存区 
  81. len:发送数据的长度 
  82. flags:该参数影响该函数的行为,可以设为 0(表示无特殊行为),MSG_DONTROUTE(标志要求传输层不要将数据路由出去),MSG_OOB(表示该数据被带外发送) 
  83. 返回值:若成功则返回发送的资料的长度,否则返回SOCKET_ERROR 
  84.  
  85. 8.closesocket()函数 
  86. int closesocket(SOCKET s);关闭套接字,释放所占资源 
  87. 返回值:成功返回0,否则返回SOCKET_ERROR 
  88. 9.shutdown()函数 
  89. int shutdown(SOCKET s, int how);用于通知对方不再发送数据,或者不再接收数据,或者既不发送也不接收数据 
  90. 参数:s:套接字 
  91. how:参数为SD_RECEIVE(表示不允许再调用接收数据函数);SE_SEND(表示不允许再调用发送数据函数);SD_BOTH(表示既不允许调用发送数据函数也不允许调用接收数据函数); 
  92. 返回值:成功返回0,否则返回-1 
  93.  
  94. 10.connect()函数 
  95. int connect(SOCKET s,const struct sockaddr FAR * name,int namelen); 
  96. 参数:s:socket的标识码 
  97. name:存储服务器的连接信息(协议族,服务器的ip,端口),服务器地址; 
  98. namelen:sockaddr结构的长度 
  99. 返回值:成功返回0,失败返回SOCKET_ERROR 
  100.  
  101. 11.字节转换函数  
  102. 在网络上面有着许多类型的机器,这些机器在表示数据的字节顺序是不同的,比如i386芯片是低字节在内存地址的低端,高字节在高端,而alpha芯片却相反.为了统一起来,则有专门的字节转换函数.  
  103. unsigned long int htonl(unsigned long int hostlong)  
  104. unsigned short int htons(unisgned short int hostshort)  
  105. unsigned long int ntohl(unsigned long int netlong)  
  106. unsigned short int ntohs(unsigned short int netshort) 
  107. 在这四个转换函数中,h代表host, n代表 network.s代表short l代表long 
  108. 第一个函数的意义是将本机器上的long数据转化为网络上的long.其他几个函数的意义也差不多 
  109.  
  110. 12.地址结构说明 
  111. typedef struct sockaddr_in 
  112. { 
  113. short sin_family;//由于我们主要使用Internet,所以一般为AF_INET 
  114. u_short sin_port;//16位端口号,网络字节顺序 
  115. struct in_addr sin_addr;//32位IP地址,网络字节顺序 
  116. char sin_zero[8];//保留 
  117. }SOCKADDR_IN; 
  118. struct in_addr  // Internet address.  
  119. {   
  120. uint32_t       s_addr;     // address in network byte order 
  121. }; 
  122. //sin_:socket address internet 
  123. struct sockaddr是通用的套接字地址,而struct sockaddr_in则是internet环境下套接字的地址形式,二者长度一样,都是16个字节。二者是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr。一般情况下,需要把sockaddr_in结构强制转换成sockaddr结构再传入系统调用函数中。  
  124. */  

你可能感兴趣的:(网络协议)