资源预览内容
第1页 / 共17页
第2页 / 共17页
第3页 / 共17页
第4页 / 共17页
第5页 / 共17页
第6页 / 共17页
第7页 / 共17页
第8页 / 共17页
第9页 / 共17页
第10页 / 共17页
亲,该文档总共17页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
linux Socket Socket编程基本实践1Socket Api基本概念什么是socket?q socket可以看成是用户进程与内核网络协议栈的编程接口。q socket不仅可以用于本机的进程间通信,还可以用于网络上不同主机的进程间通信。tcp/ip通讯模型IPv4套接口地址结构q IPv4套接口地址结构通常也称为“网际套接字地址结构”,它以“sockaddr_in”命名,定义在头文件中struct sockaddr_in uint8_t sin_len; 4sa_family_t sin_family; 4in_port_tsin_port; 2struct in_addrsin_addr; 4char sin_zero8; 8; q sin_len:整个sockaddr_in结构体的长度,在4.3BSD-Reno版本之前的第一个成员是sin_family.q sin_family:指定该地址家族,在这里必须设为AF_INETq sin_port:端口q sin_addr:IPv4的地址;q sin_zero:暂不使用,一般将其设置为0通用地址结构q 通用地址结构用来指定与套接字关联的地址。 struct sockaddr uint8_t sin_len;sa_family_t sin_family;char sa_data14; /14; q sin_len:整个sockaddr结构体的长度q sin_family:指定该地址家族q sa_data:由sin_family决定它的形式。网络字节序q 字节序大端字节序(Big Endian)最高有效位(MSB:Most Significant Bit)存储于最低内存地址处,最低有效位(LSB:Lowest Significant Bit)存储于最高内存地址处。q 小端字节序(Little Endian)最高有效位(MSB:Most Significant Bit)存储于最高内存地址 处,最低有效位(LSB:Lowest Significant Bit)存储于最低内存地址处。q 主机字节序不同的主机有不同的字节序,如x86为小端字节序,Motorola 6800为大端字节序,ARM字节序是可配置的。q 网络字节序网络字节序规定为大端字节序字节序转换函数q uint32_t htonl(uint32_t hostlong);q uint16_t htons(uint16_t hostshort);q uint32_t ntohl(uint32_t netlong);q uint16_t ntohs(uint16_t netshort);q 说明:在上述的函数中,h代表host;n代表network s代表short;l代表long地址转换函数q #include q #include q int inet_aton(const char *cp, struct in_addr *inp);q in_addr_t inet_addr(const char *cp);q char *inet_ntoa(struct in_addr in);套接字类型q 流式套接字(SOCK_STREAM)提供面向连接的、可靠的数据传输服务,数据无差错,无重复的发送,且按发送顺序接收。q 数据报式套接字(SOCK_DGRAM)提供无连接服务。不提供无错保证,数据可能丢失或重复,并且接收顺序混乱。q 原始套接字(SOCK_RAW)2SocketApi基本编程模型TCP客户/服务器模型 简单服务器模型3Socket Api基本实践Socket API基本用法socket函数q 包含头文件q 功能:创建一个套接字用于通信q 原型q int socket(int domain, int type, int protocol);q 参数q domain :指定通信协议族(protocol family)q type:指定socket类型,流式套接字SOCK_STREAM,数据报套接字SOCK_DGRAM,原始套接字SOCK_RAWq protocol :协议类型q 返回值:成功返回非负整数, 它与文件描述符类似,我们把它称为套接口描述字,简称套接字。失败返回-1bind函数q 包含头文件q 功能:绑定一个本地地址到套接字q 原型q int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);q 参数q sockfd:socket函数返回的套接字q addr:要绑定的地址q addrlen:地址长度q 返回值:成功返回0,失败返回-1listen函数q 一般来说,listen函数应该在调用socket和bind函数之后,调用函数accept之前调用。q 对于给定的监听套接口,内核要维护两个队列:q 1、已由客户发出并到达服务器,服务器正在等待完成相应的TCP三路握手过程q 2、已完成连接的队列accept函数q 包含头文件q 功能:从已完成连接队列返回第一个连接,如果已完成连接队列为空,则阻塞。q 原型q int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);q 参数q sockfd:服务器套接字q addr:将返回对等方的套接字地址q addrlen:返回对等方的套接字地址长度q 返回值:成功返回非负整数,失败返回-1connect函数q 包含头文件q 功能:建立一个连接至addr所指定的套接字q 原型q int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);q 参数q sockfd:未连接套接字q addr:要连接的套接字地址q addrlen:第二个参数addr长度q 返回值:成功返回0,失败返回-1Socket API 中的地址复用SO_REUSEADDRq 服务器端尽可能使用SO_REUSEADDRq 在绑定之前尽可能调用setsockopt来设置SO_REUSEADDR套接字选项。使用SO_REUSEADDR选项可以使得不必等待TIME_WAIT状态消失就可以重启服务器Socket服务支持多并发(多客户端连接) 分析最基本socket服务器客户端模型能否支持多客户端连接点对点聊天程序设计与实现点对点聊天程序,功能说明点对点聊天程序,设计思想4Socket Api编程进价1流协议与粘包 流协议与粘包粘包产生的原因 说明tcp字节流 无边界udp消息、数据报 有边界对等方,一次读操作,不能保证完全把消息读完。 对方接受数据包的个数是不确定的。产生粘包问题的原因1、SQ_SNDBUF 套接字本身有缓冲区 (发送缓冲区、接受缓冲区)2、tcp传送的端 mss大小限制3、链路层也有MTU大小限制,如果数据包大于MTU要在IP层进行分片,导致消息分割。4、tcp的流量控制和拥塞控制,也可能导致粘包5、tcp延迟发送机制 等等结论:tcp/ip协议,在传输层没有处理粘包问题。粘包解决方案 q 本质上是要在应用层维护消息与消息的边界q 定长包q 包尾加rn(ftp)q 包头加上包体长度q 更复杂的应用层协议编程实践q readnq writen2包头加上包体长度编程实践包头加上包体长度q 发报文时,前四个字节长度(转成网络字节序)+包体q 收报文时,先读前四个字节,求出长度;根据长度读数据。3包尾加上n编程实践n作为协议的边界q ssize_t recv(int s, void *buf, size_t len, int flags);q 与read相比,只能用于套接字文件描述符;q 多了一个flags MSG_OOB This flag requests receipt of out-of-band data that would not be received in the normal data stream. Some protocols place expedited data at thehead of the normal data queue, and thus this flag cannot be used with such protocols.带外数据 紧急指针 MSG_PEEKThis flag causes the receive operation to return data from the beginning of the receive queue without removing that data from the queue. Thus, asubsequent receive call will return the same data.可以读数据,不从缓存区中读走,利用此特点可以方便的实现按行读取数据。 一个一个字符的读,方法不好;多次调用系统调用read方法4获取本机ip相关函数getsockname & getpeername 获取本地的地址(注意是已连接以后的套接字)NAME getsockname - get socket nameSYNOPSIS #include int getsockname(int s, struct sockaddr *name, socklen_t *namelen);struct sockaddr_in localaddr;socklen_t addrlen = sizeof(localaddr);/获取本地的地址if (getsockname(sock, (struct sockaddr*)&localaddr, &addrlen) 0)ERR_EXIT(getsockname);printf(ip=%s port=%dn, inet_ntoa(localaddr.sin_addr), ntohs(localaddr.sin_port);gethostname、gethostbyname、gethostbyaddrq gethostname、gethostbyname、gethostbyaddr The domain name queries carried out by gethostbyname() and gethostb
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号