套接字编程API

来源:互联网 发布:java工程师工作职责 编辑:程序博客网 时间:2024/05/18 12:38

1. socket函数

socket函数在成功时返回一个小的的非负整数值(类似于文件描述符),称为套接字描述符(socket descriptor)。调用socket函数只是指定了协议族(IPv4,IPv6或Unix域)和套接字类型(字节流、数据报或原始套接字),并没有指定本地协议地址或远程协议地址,需要后续函数补充。

[cpp] view plaincopy
  1. #include <sys/socket.h>  
  2. /*成功则返回非负描述符,若出错则为-1*/  
  3. int socket(int family, int type, int protocol);  

family参数指明协议族;type参数指定套接字类型;protocol参数指明协议类型常值,若设为0,则让family和type的组合决定protocol。

family

说明

AF_INET

IPv4协议

AF_INET6

IPv6协议

AF_LOCAL

Unix域协议

AF_ROUTE

路由套接字

AF_KEY

密钥套接字

 

type

说明

SOCK_STREAM

字节流套接字

SOCK_DGRAM

数据报套接字

SOCK_SEQPACKET

有序分组套接字

SOCK_RAW

原始套接字

 

protocol

说明

IPPROTO_TCP

TCP传输协议

IPPROTO_UDP

UDP传输协议

IPPROTO_SCTP

SCTP传输协议

 

family和type的组合不是所有都有效的,其中 “是” 的项也是有效的,但还没找到便捷的缩略词,而空白项则是无效组合

 AF_INETAF_INET6AF_LOCALAF_ROUTEAF_KEYSOCK_STREAMTCP|SCTPTCP|SCTP是  SOCK_DGRAMUDPUDP是  SOCK_SEQPACKETSCTPSCTP是  SOCK_RAWIPv4IPv6 是是

 

AF_前缀表示地址族,PF_前缀表示协议族

 

2.connect函数

客户端通过connect函数与服务器端建立TCP连接。

[cpp] view plaincopy
  1. #include <sys/socket.h>  
  2. /*成功返回0,失败返回-1*/  
  3. int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);  

sockfd是由socket函数返回的套接字描述符。servaddr是一个指向套接字地址结构的指针,addrlen是该地址结构的大小。

connect函数导致当前套接字从CLOSED状态,转移到SYN_SENT状态,若成功再转移到ESTABILISHED状态。若connect失败则该套接字不再可用,必须关闭,不能对这样的套接字再次调用connect函数。每次调用connect失败后,都必须调用close函数关闭当前的套接字,如要再次调用connect函数,必须先重新调用socket函数。

 

3.bind函数

bind函数将本地协议地址绑定到一个套接字中。

[cpp] view plaincopy
  1. #include <sys/socket.h>  
  2. /*成功返回0,出错返回-1*/  
  3. int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);  

若指定的端口为0,那么内核就在bind函数被调用时选择一个临时端口。若指定IP地址为通配地址,内核将等到套接字已连接(TCP)或已在套接字上发出数据报(UDP)时,才选择一个本地IP。

 

4.listen函数

listen函数仅会被TCP服务器端调用,主要完成两件事情1).当socket函数创建一个套接字时,它被假设为主动套接字,既是将调用connect函数发起连接的客户套接字,而listen函数把一个未连接的套接字转换成一个被动套接字,指示内核应该接受指向该套接字的连接请求。2)listen函数的第二个参数规定了内核应该为相应套接字排队最大连接个数。

[cpp] view plaincopy
  1. #include <sys/socket.h>  
  2. /*成功返回0,失败返回-1*/  
  3. int listen(int sockfd, int backlog);  


 5.accept函数

 accept函数由TCP服务器调用,用于从已完成连接队列队头返回下一个已完成连接。如果已完成连接队列为空,则进程进入睡眠。

[cpp] view plaincopy
  1. #include <sys/socket.h>  
  2. /*成功返回非负描述符,失败返回-1*/  
  3. int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);  

如果accept成功,那么其返回值是由内核自动生成的一个全新描述符,代表与所返回客户的TCP连接。sockfd参数为监听套接字(listening socket)描述符(由socket函数创建),accept函数返回值为已连接套接字(connected socket)描述符。一个服务器通常仅仅创建一个监听套接字,它在服务器的生命周期一直存在。内核为每个由服务器进程接受的客户连接创建一个已连接套接字(此时TCP三路握手已经完成)。当服务器完成对某个给定客户的服务时,相应的已连接套接字就会被关闭。

 6.fork和exec函数

 在Unix系统中的fork函数是产生新进程的唯一方法。

[cpp] view plaincopy
  1. #include <unistd.h>  
  2. /*若成功在子进程中返回0,在父进程中返回子进程ID, 若失败返回-1*/  
  3. pid_t fork(void);  

fork函数返回两次,它在调用进程(既是父进程)中返回一次,返回值是新派生进程(既是子进程)的进程ID号;在子进程又返回一次,返回值为0。因此返回值本身告知当前进程是子进程和父进程。子进程可以通过getppid取得父进程ID,而父进程可以有多个子进程并且无法获取各个子进程的进程ID。如果父进程想要跟踪所有 子进程的进程ID,那么必须记录每次调用fork大端返回值。

 父进程中调用fork之前打开的所有描述符在fork返回之后由子进程分享。网络服务器利用了这个特性:父进程调用accept之后调用fork。所接受的已连接套接字随后就在父进程和子进程之间共享。通常情况下,子进程接着读写这个已连接套接字,父进程则关闭这个已连接套接字。

子进程和父进程都执行在fork函数调用之后的代码,子进程是父进程的一个拷贝。例如,父进程的数据空间、堆栈空间都会给子进程一个拷贝,而不是共享这些内存。

fork有两个典型用法:

1.一个进程创建一个自身的副本,这样每个副本都可以在另一个副本执行其他任务的同时处理各自的某个操作。

2.一个进程想要执行另一个程序。既然创建新进程的唯一办法就是调用fork,该进程于是首先调用fork创建一个自身的副本,然后其中一个副本(通常为子进程)调用exec把自身替换成新的程序。

 

存放在硬盘上的可执行程序文件能够被Unix执行的唯一方法便是由一个现有进程调用六个exec函数中的一个。exec把当前进程映像替换成新的程序文件,而且该新程序通常从main函数开始执行。进程ID不改变。调用exec的进程为调用进程(calling process),称新执行的程序为新程序(new program)。

6个exec函数之间的区别在于:1)待执行的程序文件是由文件名(filename)还是有路径名(pathname);2)新程序的参数是一一列出还是由一个指针数组来引用; 3)把调用进程的环境传递给新程序还是给新程序指定新的环境。

[cpp] view plaincopy
  1. #include <unistd.h>  
  2. /*若成功则不返回,若失败则返回-1*/  
  3. int execl(const char *pathname, const char *arg0, ...);  
  4. int execv(const char *pathname, char *const *argv[]);      
  5. int execle(const char *pathname, const char *arg0, ..., char *const envp[]);    
  6. int execve(const char *pathname, char *const argv[], char *const envp[]);   
  7. int execlp(const char *filename, const char *arg0,...);  
  8. int execvp(const char *filename, char *const argv[]);  
  9.    

 其中只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。

 

7.close函数

 close函数用来关闭套接字,并终止TCP连接

[cpp] view plaincopy
  1. #include <unistd.h>  
  2. /*成功则返回0, 出错则返回-1*/  
  3. int close(int sockfd);  

 

8.getsockname函数

getsockname返回某个套接字关联的本地协议地址

[cpp] view plaincopy
  1. #include <sys/socket.h>  
  2. /*成功则返回0,失败则返回-1*/  
  3. int getsockname();  


 

9.getpeername函数

getpeername返回与某个套接字关联的外地协议地址

[cpp] view plaincopy
  1. #include <sys/socket.h>  
  2. /*成功则返回0,失败则返回-1*/  
  3. int getpeername();  
0 0