socket 定义socket 类型字节序 套接口地址结构 服务名称数据结构 socket 通信原理 socket 编程函数 图解
粉丝不过w
socket 定义
socket :建立在传输层之上为应用开发人员提供的网络数据传输的接口, 是一种文件描述符,如:请示要尚方宝剑,这样我就可以在皇上的朝廷上 为所欲为
Socket 类似于打开文件的函数调用—Socket(),该函数返回一个整型的Socket 描述符,然后 连接建立数据传输等操作都是通过该 Socket 描述符实现,如:我要为所欲为的时候,那必须要拿到这个尚方宝剑,这样我就可以纵横网络
socket 类型
流式 socket—SOCK_STREAM(面向连接的 TCP 服务应用) 和数据报式
字节序
计算机数据存储有两种字节优先顺序: 高位字节优先( 大端 )和 低位字节优先( 小端 ),如:皇上想要身材高的妃子先来,还是要身材娇小的妃子先来
以 int a = 0x 053010
大端:
字节号 | 0 | 1 | 2 |
数据 | 05 | 30 | 10 |
小端:
字节号 | 0 | 1 | 2 |
数据 | 10 | 30 | 05 |
判断大小端机:
#include <stdio.h>
#include <stdlib.h>
int main()
{
if(isLittleEndian())
{
printf("Little Endian\n");
}
else
{
printf("Big Endian\n");
}
return 0;
}
int isLittleEndian()
{
unsigned short i = 1;
return(1 == *((char *)&i));
}
网络传输数据以网络字节序(高位字节优先顺序)来传输的,所以 数据发送端要将数据变为网络字节序,在接收端要将网络字节序变成主机字节序,如:皇上在上朝,要高的妃子先来,但后宫是以低的优先,那从后宫到朝上就要变成高的妃子优先,但朝上到后宫就要变成低的妃子
字节顺序转换函数:
//Host to Network Short
htons()
// Host to Network long
htonl()
// Network to Host Short
ntohs()
// Network to Host Long
ntohl()
h:" host " , n :" network ", s :" short ", l : " long "
套接口地址结构
//通用套接口地址
struct sockaddr
{
unsigned short sa_family; /* 地址族, AF_xxx */
char sa_data[14]; /* 14 字节的协议地址 */
};
//常用套接口地址
struct sockaddr_in
{ //“in” 代表“Internet”
short int sin_family; /* 地址族,AF_xxx */
unsigned short int sin_port; /* 端口号 */
struct in_addr sin_addr; /* IP 地址 */
unsigned char sin_zero[8]; /* 填充 0 以保持与 struct sockaddr 同样大小 */
};
// 专门用来存储 IP 地址
struct in_addr
{
unsigned long s_addr;
};
服务名称数据结构
truct hostent
{
char *h_name; /* 主机的正式名称 */
char *h_aliases; /* 主机的别名 */
int h_addrtype; /* 主机的地址类型 AF_INET*/
int h_length; /* 主机的地址长度 对于 IP4 是 4 字节 32 位*/
char **h_addr_list; /* 主机的 IP 地址列表 */
};
#define h_addr h_addr_list[0] /* 主机的第一个 IP 地址*/
socket 通信原理
socket 编程函数
打开套接字
#include <sys/socket.h>
/*
*function:
* 为网络通讯做基本的准备
*parameter:
* domain: 通讯协族 AF_UNIX AF_INET
* type: 通讯协议
* SOCK_STREAM TCP 协议,按顺序的,可靠,双向,面向连接的比特
* SOCK_DGRAM UDP 协议,定长的,不可靠,无连接的通信
* SOCK_RAW 原始套接字,直接访问 IP 协议
* rotocol: 指定 type,填 0
*return:
* 成功: 文件描述符
* 失败: -1
*/
int socket(int domain, int type,int protocol)
绑定套接字
/*
*function:
* 本地的端口同 socket 返回的文件描述符捆绑在一起
*marapeter:
* sockfd: socket 调用返回的文件描述符
* addrlen: sockaddr 结构的长度
* my_addr: 一个指向 sockaddr 的指针
*return:
* 成功: 0
* 失败: -1
*/
int bind(int sockfd, struct sockaddr *my_addr, int addrlen)
监听 Listen
/*
*function:
* bind 的文件描述符变为监听套接字
*parameter:
* sockfd: bind 后的文件描述符
* backlog:设置请求排队的最大长度
*/
int listen(int sockfd,int backlog)
接收(accept)
/*
*parameter:
* sockfd:是 listen 后的文件描述符
*return:
* 成功: 返回最后的服务器端的文件描述符
* 失败: -1
*note:
* 服务器端会一直阻塞到有一个客户程序发出了连接
*/
int accept(int sockfd, struct sockaddr *addr, int *addrlen);
连接(connect)
/*
*function:
* 客户端用来同服务端连接
*parameter:
* sockfd: socket 返回的文件描述符
* serv_addr: 储存了服务器端的连接信息, sin_add 是服务端的地址
* addrlen: serv_addr 的长度
*return:
* 成功: 0, sockfd 是同服务端通讯的文件描述符
* 失败: -1
*/
int connect(int sockfd, struct sockaddr * serv_addr,int addrlen)
面向连接的读写数据函数
Send()函数
/*
*parameter:
* sockfd: 传输数据的 socket 描述符
* msg: 一个指向要发送数据的指针
* len : 数据的长度,单位:字节
* flags: 一般为 0
*return:
* 实际上发送出的字节数
*/
int send(int sockfd, const void *msg, int len, int flags);
recv()函数
/*
*parameter:
* sockfd: 接受数据的 socket 描述符
* buf: 存放接收数据的缓冲区
* len : 缓冲的长度
* flags: 置为 0
*return:
* 成功:实际上接收的字节数
* 错误:-1
*/
int recv(int sockfd, void *buf, int len, unsigned int flags);
面向无连接的读写数据函数
无连接的数据报 socket 方式下,由于本地 socket 并没有与远端机器建立连接,所以在发送数据时要指指明的地址,如:皇上去某妃子后宫,并没有要巍公公通报后宫,皇上要去花妃子后宫,这样可能导致花妃子没有化妆,就失宠
sendto()函数
/*
*parameter:
* to: 目地机的 IP 地址和端口号信
* tolen: sizeof (struct sockaddr)
*return:
* 成功:实际发送的数据字节长度
* 失败:-1
*/
int sendto(int sockfd,
const void *msg,
int len,
unsigned int flags,
const struct sockaddr *to,
int tolen);
recvfrom()函数
/*
*parameter:
* from:源机的 IP 地址及端口号
* fromlen: sizeof (struct sockaddr)
*return:
* 成功:接收到的字节数
* 失败:-1
*/
int recvfrom(int sockfd,
void *buf,
int len,
unsigned int lags,
struct sockaddr *from,
int *fromlen)
面向连接的读写数据函数
close()函数来释放该 socket,停止在该socket 上的任何数据操作: close(sockfd);如:看见花妃子这个样子,皇上拔腿就跑呀,以后再也不来了
shutdown()函数来关闭该 socket。 该函数允许你只停止在某个方向上的数据传输, 而一个方向上的数据传输继续进行。如:皇上看见花妃子的样子,皇上扫兴呀,然后要花妃子化妆好了来朕的寝宫
/*
*parameter:
* how:
* 0: 不允许继续接收数据
* 1: 不允许继续发送数据
* 2: 不允许继续发送和接收数据
*return:
* 成功:0
* 失败:-1
*/
int shutdown(int sockfd,int how);
DNS——域名服务相关函数
由于 IP 地址难以记忆和读写,所以为了读写记忆方便,人们常常用域名来表示主机,这就需要进行域名和 IP 地址的转换。如:皇上的妃子很多,皇上记不住呀,就叫的小花,小白,小绿.....
#define h_addr h_addr_list[0] /*在 h-addr-list 中的第一个地址*/
struct hostent
{
char *h_name; /* 主机的官方域名 */
char **h_aliases; /* 一个以 NULL 结尾的主机别名数组 */
int h_addrtype; /* 返回的地址类型,在 Internet 环境下为 AF-INET */
int h_length; /* 地址的字节长度 */
char **h_addr_list; /* 一个以 0 结尾的数组,包含该主机的所有地址*/
};
/*
*return:
* 成功:指向 struct hosten 的指针
* 失败:-1
*note:
* herror(): 输出错误信息
*/
struct hostent *gethostbyname(const char *name);