1 套接字地址结构
struct sockaddr{
unsigned short sa_family;//地址类型
char sa_data[14]; //14字节的地址协议}
sa_family表示套接字的协议族类型,对应于TCP/IP的协议该是AF_INET;
与该结构体等价的另一个数据结构:sockaddr_in。
struct sockaddr_in
{
unsigned short sin_family; //地址类型
unsigned short sin_port ; //端口号
struct in_addr sin_addr ;//IP地址
unsigned char sin_zero[8];//填充字节,一般为0
}
struct in_addr {
unsigned long s_addr;
};
结构体sockaddr和结构体sockaddr_in都是16个字节。通常在编写基于TCP/IP协议的网络程序的时候,使用sockaddr_in来设置地址,然后通过类型的强制转换成sockaddr类型。
struct sockaddr_in sock;
sock.sin_family = AF_INET;
sock.sin_port = htons(80);
sock.sin_addr.s_addr = inet_addr("202.112.12.11");
memset(sock.sin_zero, 0, sizeof(sock.sin_zero)); //将数组sin_zero设置成为0
2 创建套接字
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
domain用来表示套接字所使用的协议族。AF_UNIX:在本机通讯的套接字;AF_INET:使用ipv4; AF_INET6:使用ipv6。
type指示套接字的类型。SOCK_STREAM SOCK_DGRAM SOCK_RAW
3 建立连接
函数connect用来在一个执行的套接字上穿件一个连接。
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
服务器的IP地址和端口号由serv_addr来制定。
4 绑定套接字
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
这个函数只有服务器端使用。
5 在套接字上侦听
int listen(int s, int backlog);
在服务器端,一般先创建一个socket,然后调用函数bind将该套接字绑定到某个端口上,接着调用listen函数等待来自于客户端的连接请求。
一般多个客户端连接到一个服务器,服务器设置一个连接队列,记录已经建立的连接,参数backlog指定了该连接队列的最大长度。如果连接队列已经达到最大,
之后的连接请求将会被服务器拒绝。
6 接受连接
int accept(int s, struct sockaddr *addr, socklen_t *addrlen);
参数s是由函数socket创建,经函数bind绑定到本地某一端口上,然后通过函数listen转化而来的监听套接字。
参数addr是用来保存发起连接请求的主机的地址和端口。
参数addrlen是addr所指向的结构体的大小。
只能对面向连接的套接字使用accept函数。accept成功时,将创建一个新的套接字,并为这个新的套接字分配一个新的套接字描述符,类似文件描述符,进程可以利用这个新的套接字描述符与客户端交换数据。参数S指定的套接字将继续等待客户端的连接请求。
如果参数s指向的套接字被设置成为阻塞方式(Linux默认的设置),且连接请求队列为空的时候,则accept函数将被阻塞直到有连接请求为止;
如果参数s指向的套接字被设置成为非阻塞方式(fcntl),如果队列为空,则accept立即返回-1,errno设置成为EAGAIN。
7 TCP套接字 发送数据
size_t send(int s, const void *msg, size_t len, int flags);
函数send只能对处于连接状态的套杰斯使用。参数S为已建立好连接的套接字描述符,即accept函数的返回值。
参数msg指向存放待发数据的缓冲区,参数len为待发数据的长度。
如果要发送的数据太长而不能发送时,将出现错误,error设置成为EMSGSIZE;
如果要发送的数据长度大于该套接字的缓冲区剩余空间大小时,send()一般会被阻塞,如果该套接字设置成为非阻塞方式,则此时立即返回-1.
执行成功则返回实际发送的数据的字节数。
执行成功只能说明数据写入套接字的缓冲区中,并不表示数据已经成功的通过网络发送到目的地。
8 接受数据
size_t recv(int s, coid *buf, size_t len, int flags);
如果一个数据包太长以至于缓冲区放不下的时候,剩余部分的数据将可能被丢弃。
如果在指定的套接字上无数据到达时,recv函数将被阻塞,如果套接字设置成为非阻塞的话,则立即返回-1;