您的位置:首页 > 理论基础 > 计算机网络

基本TCP套接口编程

2013-01-20 15:56 239 查看
1.#include<sys/socket.h>

int socket (int family, int type, int protocol);

返回值,成功为非负整数,成为套接口描数字;出错为-1、

family参数:

AF_INET --ipv4;

AF_INET6--ipv6;

AF_LOCAL--unix域协议;

AF_ROUTE--路由socket;

AF_KEY--密钥socket;

type参数:

SOCK_STREAM--字节流套接口

SOCK_DGRAM--数据报套接口

SOCK_RAM--原始套接口

protocal参数一般置为0,当type为SOCK_RAM时不同.

2.#include<sys/socket.h>

int connect (int sockfd, const struct sockaddr* servaddr, socklen_t addlen);

返回值,0-成功;-1-出错;

servaddr参数可以为sockaddr_in和sockaddr_in6类型,但是都必须强制转化为sockaddr指针类型;

connect函数的出错处理:

(1)ETIMEOUT-connection timed out 目的主机不存在,没有返回任何相应,例如主机关闭

(2)ECONNREFUSED-connection refused(硬错)到达目的主机后,由于各种原因建立不了连接,主机返回RST(复位)响应,例如主机监听进程未启用,tcp取消连接等

(3)EHOSTTUNREACH-no route to host(软错)路由上引发了一个目的地不可达的ICMP错误

其中(1)(3),客户端会进行定时多次重试,一定次数后才返回错误。另外,当connect连接失败时,sockfd套接口不可用,必须关闭后重新socket分配才行。

3.#include<sys/socket.h>

int bind (int sockfd, const struct sockaddr *addr, socklen_ t addrlen);

bind函数为套接口分配一个本地地址和端口

对于TCP协议,本地IP和端口可以不指定,主机会自动分配!

一般来说,我们会给服务器指定一个监听地址结构,以让客户端可以建立连接;连接建立后再分配一个临时端口作为数据传输通道。

而对于客户端来说,一般不bind本地地址,而是让内核根据输出协议自动选定本地ip和端口。

当ip地址和端口设置为通配符时,表示由内核自动分配:

(1)对于端口,设置为0表示通配符

(2)ip地址,对于ipv4,通配符表示如下:

struct sockaddr_in scr;

scr.sin_addr.s_addr=htonl (INADDR_ANY);

对于ipv6,通配符表示如下:

struct sockaddr_in6 scr;

scr.sin6_addr=in6addr_any;

4.#include<sys/socket.h>

int listen (int sockfd, int backlog);

backlog为最大连接个数,包括正在建立的连接和已经建立但是还未进行accept函数的连接,即处于三次握手机制和accept函数之间。

listen函数将sockfd套接口由主动模式变成被动监听模式,使内核能接受指向此套接口的连接请求 。

当队列已满时,服务器不会对新来的SYN有任何回应(包括RST),从而使得客户端延时重发SYN。

5.#include<sys/socket.h>

int accept (int sockfd, struct sockaddr * addr, socklen_t *len);

成功,返回非负描数字,称为已连接套接口;-1表示出错

sockfd为listen函数后的监听套接口;

addr和len参数都为 值-结果 参数;

addr返回客户进程的协议地址,功能类似getpeername函数

len参数调用前是addr的长度,返回后是内核读取的addr结构的准确字节数。

如果对客户进程不感兴趣,addr‘len可设为NULL;

accept函数返回一个由内核自动生成的新描述字,称为 已连接套接口;

一般来说,sockfd称为监听套接口,在服务器进程一直存在;accept返回的已连接套接口,在服务器子进程中存在,一旦子进程连接结束,此套接口也关闭。

6.通常的处理,服务器当进程accept后,会fork一个子进程,同时,父进程关闭已连接套接口,子进程关闭监听套接口,这样2个进程就能各司其职:父进程继续监听,子进程完成连接操作。

connfd=accept(sockfd,...,...);

if (fork()==0){    //子进程

close(sockfd);

处理过程。。。

close(connfd);

}

close(connfd);//父进程

7。我们可以通过getsockname函数来获得套接口的本地ip信息,通过getpeername函数来获得连接另外一端的ip信息。

#include<sys/socket.h>

int getsockname (int sockfd, struct sockaddr *addr, socklen_t *len);

得到套接口关联的本地地址结构

int getpeername (int sockfd, struct sockaddr *addr, socklen_t *len);

得到远程协议地址结构   len为struct sockaddr的长度

当中的sockfd必须是已连接套接口,不能是监听套接口。

8.int close (int sockfd);

close只是减少某个套接口的计数,只有当计数为0时,内核才会向对方主机发送FIN。。。

如果确实需要发送FIN,那可以使用shutdown函数

int shutdown(int sockfd, int flags);

flags为SHUT_WR,  SHUT_RD,  SHUT_RDWR..关闭套接口的相应功能,(读,写),并发送FIN,不管计数是否为0。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: