TCP网络编程API----socket

  • 网络层的IP地址可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样可以利用三元组(IP地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志(socket)与其它进程进行交互
  • 网络中的进程通过socket进行通信,那么什么是socket呢?socket其实就是一种特殊的文件,一些socket函数即是对其进行的操作(读/写、打开、关闭)
  • 就目前而言,几乎所有的应用程序都是采用socket

下面就来简单了解一下在Tcp协议通信的socket

TCP交互流程

TCP交互流程

上述展示的交互流程,具体如下:

  • 1.服务器根据地址类型(ipv4,ipv6)、socket类型、协议创建socket
  • 2.服务器为socket绑定IP地址和端口号
  • 3.服务器socket监听端口号请求,随时准备接收客户端发来的请求,这时候服务器socket并没有打开
  • 4.客户端创建socket
  • 5.客户端打开socket,根据服务器IP地址和端口号试图连接服务器socket
  • 6.服务器socket接收到客户端socket请求,被动打开,开始接受客户端请求,直到客户端返回连接信息。这时候socket进入阻塞状态,所谓阻塞即accept()方法一直到客户端返回连接信息后才返回,开始接收下一个客户端请求
  • 7.客户端连接成功,向服务器发送连接状态信息
  • 8.服务器accept方法返回,连接成功
  • 9.客户端向socket写入信息
  • 10.服务器读取信息
  • 11.客户端关闭
  • 12.服务器端关闭

可以看出,服务器端socket与客户端socket建立连接的部分其实就是TCP的三次握手

socket接口函数

  1. socket函数
int socket(int domain, int type, int protocol);
  • socket函数对应于普通文件的打开操作。普通文件的打开操作返回一个文件描述字,而socket()用于创建一个socket描述符,它唯一标识一个socket
  • 创建socket时,指定不同的参数创建不同的socket描述符,socket函数的3个参数:
  • 1.domain:即协议域,又称为协议族。常用的协议族有:AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,unix域socket)、AF_ROUTE等。协议族决定了socket的地址类型
  • 2.type:指定socket的类型。常用的socket类型有:SOCK_STREAM(Tcp协议)、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等
  • 3.protocol:指定协议。常用的协议有:IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,分别对应Tcp传输协议、UDP传输协议、STCP传输协议、TIPC传输协议

protocol为0时,会自动选择type类型对应的默认协议

  • 当调用一个socket函数用来创建一个socket时,返回的socket描述字它存在于协议族中,但没有一个确定的地址。可以利用bind()函数赋予给它一个地址,否则系统将在调用connect()、listen()时随机分配一个端口
  • 每个进程在自己的进程空间里都有一个套接字描述符表,但是套接字数据结构都存放在操作系统的内核缓冲里
  1. bind函数
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • (1).sockfd:即socket描述字,它是通过socket()函数创建来唯一标识一个socket的。bind()函数是给这个描述字绑定一个名字
  • (2).addr:一个const struct sockaddr*指针,指向要绑定给sockfd的协议地址,有以下几种:

ipv4对应的如下代码:

struct sockaddr_in {
	sa_family_t  sin_family;  //address familry: AF_INET
	in_port_t  sin_port;     //port in network byte order 
	struct  in_addr  sin_addr; //internet address
};
struct  in_addr {
	uint32_t  s_addr;  //address in network byte order
};

ipv6对应的代码:

struct sockaddr_in {
	sa_family_t  sin6_family;  //AF_INET6
	in_port_t  sin6_port;     //port number
	uint32_t  sin6_flowinfo      //ipv6 flow information
	struct  in6_addr  sin6_addr; //Ipv6 address
	uint32_t  sin6_scope_id;        //scope id (new in 2.4)
};
struct  in6_addr {
	unsigned char  s6_addr[16];      //Ipv6address
};

UNIX域对应的代码:

#define UNIX_PATH_MAX  108
struct sockaddr_un  {
	sa_family_t  sun_family;      //AF_UNIX
	char  sun_path[UNIX_PATH_MAX];     //pathname
};
  • (3).addrlen:对应的地址长度
  1. listen和connect函数
int listen(int sockfd, int backlog);
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • listen函数的第一个参数即为要监听的socket描述字,第二个参数为相应的socket可以排队的最大连接个数。socket函数创建的socket默认是一个主动类型的,listen函数将其变为被动的,等待客户的连接请求
  • connect函数的第一个参数为客户端的socket描述字,第二参数为服务器的socket地址,第三个参数为socket地址的长度。客户端通过调用connect函数来建立与TCP服务器的连接
  1. accept函数
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

accept函数的第一个参数为服务器的socket描述字,第二个参数为指向struct sockaddr*的指针,用于返回客户端的协议地址;第三个参数为协议地址的长度。如果accept成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的Tcp连接

  1. read和write函数

网络I/O操作有下面几组:

read()/write()
recv()/writev()
readv()/writev()
recvmsg()/sendmsg()
recvfrom()/sendto()

最常用的则是write()和read(),read原型如下:

ssize_t read(int fd, void *buf, size_t count);

read()函数负责从fd中读取内容。当读取成功时,read()返回实际所读的字节数,如果返回的值是0表示已经读到文件的结束了,小于0表示出现了错误。三个参数分别表示(1)socket描述字fd (2)缓冲区buf (3)缓冲区长度count

write()原型:

ssize_t write(int fd, const void *buf, size_t count);

write函数将buf中的nbytes写入文件描述字fd成功时返回写的字节数。失败时返回-1,并设置errno变量,当我们向套接字文件描述符写时有两种可能:(1)write的返回值大于0,表示写了部分或者是全部的数据 (2)返回的值小于0,此时出现了错误。三个参数分别表示:(1)fd表示socket描述字 (2)buf表示缓冲区 (3)count表示缓冲区长度

  1. close函数
#include <unistd.h>  //头文件
int close(int fd);  

close一个TCP socket的默认行为时,会把该socket标记为已关闭,然后立即返回到调用进程。该描述字不能再由调用进程使用,也就是说不能再作为read或write的第一个参数

close操作只是使相应的socket描述字的引用计数-1,只有当引用计数为0时,才会触发TCP的客户端向服务器发送终止连接请求

--------------------------------------------get------------------------------------------------------

了解TCP交互流程
简单编写一个TCP server

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值