【网络编程二】网络通信常用的函数总结

1、函数socket

函数原型:

int socket(int domain, int type, int protocol);
参数说明:
domain:协议域,又称协议族(family)。常用的协议族有AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域Socket)等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。
type:指定Socket类型。常用的socket类型有SOCK_STREAM、SOCK_DGRAM等。流式Socket(SOCK_STREAM)是一种面向连接的Socket,针对于面向连接的TCP服务应用。数据报式Socket(SOCK_DGRAM)是一种无连接的Socket,对应于无连接的UDP服务应用。
protocol:指定协议。常用协议有IPPROTO_TCP、IPPROTO_UDP等,分别对应TCP传输协议、UDP传输协议。
注意:type和protocol不可以随意组合,如SOCK_STREAM不可以跟IPPROTO_UDP组合。当第三个参数为0时,会自动选择第二个参数类型对应的默认协议。

 返回值:

如果调用成功就返回新创建的套接字的描述符,如果失败就返回INVALID_SOCKET(Linux下失败返回-1)。套接字描述符是一个整数类型的值。每个进程的进程空间里都有一个套接字描述符表,该表中存放着套接字描述符和套接字数据结构的对应关系。该表中有一个字段存放新创建的套接字的描述符,另一个字段存放套接字数据结构的地址,因此根据套接字描述符就可以找到其对应的套接字数据结构。每个进程在自己的进程空间里都有一个套接字描述符表但是套接字数据结构都是在操作系统的内核缓冲里。

2、函数bind(给socket绑定一个地址结构 即ip+port)

函数原型:
int bind(SOCKET socket, const struct sockaddr* address, socklen_t address_len);
参数说明:
socket:是一个套接字描述符。
address:是一个sockaddr结构指针,该结构中包含了要结合的地址和端口号。
address_len:确定address缓冲区的长度。
返回值:
如果函数执行成功返回值为0,否则失败返回为SOCKET_ERROR

因为在bind函数中要使用参数sockaddr,所以这里有必要说一下:socketaddr与socketaddr_in

(1)sockaddr在头文件#include <sys/socket.h>中定义,sockaddr的缺陷是:sa_data把目标地址和端口信息混在一起了,如下:

1 struct sockaddr
2 {  
3        sa_family_t sin_family;    //地址族
4       char sa_data[14];          //14字节,包含套接字中的目标地址和端口信息               
5 }; 

(2)sockaddr_in在头文件 #include<netinet/in.h>或 #include<arpa/inet.h>中定义,该结构体解决了sockaddr的缺陷,把port和addr分开储存在两个变量中,如下: 

socketaddr与socketaddr_in二者长度一样,都是16个字节,即占用的内存大小是一致的,因此可以互相转化。二者是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr。

举例:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <sys/socket.h>
 4 #include <netinet/in.h>
 5 
 6 int main(int argc,char **argv)
 7 {
 8     int sockfd;
 9     struct sockaddr_in mysock;
10 
11     sockfd = socket(AF_INET,SOCK_STREAM,0);  //获得fd
12 
13     bzero(&mysock,sizeof(mysock));  //初始化结构体
14     mysock.sin_family = AF_INET;  //设置地址家族,要与socket第一个参数一致
15     mysock.sin_port = htons(800);  //设置端口---使用htons将主机字节序转为网络字节序
16     mysock.sin_addr.s_addr = inet_addr("192.168.1.0");  //设置地址---inet_addr函数可以将一个字符串类型的ip转化为一个网络字节序的整数值
17     bind(sockfd,(struct sockaddr *)&mysock,sizeof(struct sockaddr); /* bind的时候进行转化 */
18     ... ...
19     return 0;
20 }

另外给ip port赋值还有如下的方法:

3、函数listen(设置同时与服务器建立连接的上限数,即同时进行3次握手的客户端的数量)

#include <sys/socket.h>
int listen( int sockfd, int backlog);
参数:
sockfd:用于标识一个已捆绑未连接套接口的描述字。
backlog:等待连接队列的最大长度。
返回值:
如无错误发生,listen()返回0。否则的话,返回-1,
4、函数accept(阻塞监听客户端建立连接
(注意这个函数形参接收一个struct sockaddr *addr,这个参数是作为传出参数的,传出建立好连接的客户端的ip + port信息)
SOCKET accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数
sockfd:套接字描述符,该套接口在listen()后监听连接。
addr:(可选)指针,指向一缓冲区,其中接收为通讯层所知的连接实体的地址。Addr参数的实际格式由套接口创建时所产生的地址族确定。
addrlen:(可选)指针,输入参数,配合addr一起使用,指向存有addr地址长度的整型数。传出建立好连接的客户端的ip + port信息的大小。
 
返回值:成功返回能与服务器进行通信的socket对应的文件描述符(新的文件描述符)
            失败返回-1

如果accept成功后,在服务器端存在两个socket描述符。

5、(客户端)函数connect(用于建立与指定服务器socket进行连接)

头文件: #include <sys/socket.h>
函数原型: int connect(SOCKET s, const struct sockaddr * name, int namelen);
参数:
s:标识一个未连接socket(在客户端起的socket函数的返回值)。
name:传入参数,服务器的地址结构。
namelen:服务器的地址结构字节长度。

connect()用来将参数sockfd 的socket 连至参数serv_addr 指定的网络地址。
返回值:成功则返回0, 失败返回-1, 错误原因存于errno 中。

注意:在客户端我们并没有使用bind函数绑定自己的ip+port,这是系统自动分配的。所谓的“隐式绑定”。

【TCP通信流程】

server端:

  1、socket()  创建socket

  2、bind()   绑定服务器地址结构

  3、listen()   设置监听上限

  4、accept()     阻塞监听客户端的连接

  5、read(fd)      读取socket获取客户端数据

  6、处理读取到的数据

  7、write(fd)      回写数据

  8、close()

client端:

  1、socket()  创建socket

  2、connect()  与服务器建立连接

  3、write()   写数据到socket

  4、read()    读服务器端回写的数据

  5、close() 

文章参考:

http://www.it165.net/pro/html/201211/4066.html

http://www.cnblogs.com/huqian23456/archive/2011/02/22/1961822.html

原文地址:https://www.cnblogs.com/xuelisheng/p/10325660.html