回顾前面学的进程间的通信,依赖与Linux内核,无法实现多机通信,如:Linux与安卓、Linux与单片机、Linux与Linux等,所以引出网络通信,网络通信需要地址(即ip地址与端口号),协议(http、TCP、UDP)。
TCP和UDP
对比:
1.TCP面向连接(如打电话);UDP是无连接,发送之前无需连接。
2.TCP可靠性高,传送数据无差错,不丢失,不重复,且按序到达;UDP数据传送可能会丢失,如传输视频,丢失小部分bit对视频并不会造成太大的影响。
3.TCP连接仅适用于点对点;UDP支持一对一、一对多、多对一和多对多的交互通信。
4.TCP首部开销20字节;UDP首部开销小,只有8字节。
5.TCP的通信信道是全双工的可靠信道;UDP是不可靠信道。
6.TCP面向字节流,TCP把数据看成一连串无结构的字节流;UDP面向报文,UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如实时视频,IP电话等)。
端口号的作用:主机上运行许多服务,如Web服务、FTP服务、SMTP服务等,通过"IP地址+端口号"区分不同的服务,端口设置一种访问通道。
字节序
概述:字节序是多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。
常见序:分为小端字节序和大端字节序号 网络字节序=大端字节序
小端字节序:将低序字节存放在起始位置 大端字节序:将高序字节存放在起始位置
Socket编程
Socket开发步骤:1.创建套接字(获取网络描述符) 2.为套接字添加信息(IP和端口号) 3.监听网络连接 4.监听到客户端接入,接受连接 5.数据交互 6.关闭套接字,断开连接
网络编程使用的API:
服务器
1.创建套接字
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol) //成功返回描述符,失败返回-1,设置errno描述宏
参数domain:表示协议或地址族,对于TCP/IP通常为AF_INET,与socket_addr中的sin_family的含义和取值一样
参数type:表示套接字类型,对于TCP为SOCK_STREAM;对于UDP为SOCK_DGRAM;对于原始套接字为SOCK_RAW
参数protocol:表示使用的协议号,用0指定前两个参数的默认协议号
2.绑定本地地址
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
//成功返回0,失败返回-1,并设置errno为EADDRINUSER,常见错误为端口被占用
参数sockfd:socket()函数返回的套接字描述符
参数addr:addr是指向struct sockaddr结构体的指针,结构体包含名称、端口、IP地址
参数addrlen:套接字地址接口的长度,可以设置为sizeof( struct sockaddr )
cd /usr/include/ grep "sockaddr_in {" * -nir 查找包含结构体sockaddr_in的头文件<linux/in.h>
地址转换API
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp); //字符串"xx.xx.xx.xx"转换为网络能识别的格式char *inet_ntoa(struct in_addr in); //网络格式转换为字符串"xx.xx.xx.xx"
3.监听连接
#include <sys/types.h>
#include <sys/socket.h>
int listen(int sockfd, int backlog); //成功返回0,失败返回-1,并设置errno描述
参数sockfd:socket()函数返回的套接字描述符
参数backlog:未经过处理的连接请求队列的最大容量,通常设置为5-10
4.连接(默认阻塞)
#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//返回新的套接字描述符,并将连接客户端的信息填入addr指向的内存空间
参数sockfd:socket()函数返回的套接字描述符
参数addr:指向struct sockaddr_in结构体的指针,用来返回已连接客户端的协议地址
参数addrlen:客户端地址的长度
5.数据收发
使用read()、write()函数,前面学习过...
6.关闭连接
#include <unistd.h>
int close(int sockfd);
客户端
1.客户端的connect函数
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *sevr_addr,socklen_t addrlen);
//成功返回0,失败返回-1,并设置errno描述
参数sockfd:socket()函数的套接字描述符
参数sevr_addr:服务器端的IP地址和端口号的地址结构体指针
参数addrlen:sevr_addr结构体所占内存大小,可以设置为sizeof( struct sockaddr )
练习:socket服务端代码实现
练习:socket服务端收发功能实现
程序运行,终端输入:telnet ip地址 端口号
练习:客户端代码实现
分别运行client 和 server
练习:双方聊天功能实现
q_server.c
q_client.c
练习:多方消息收发,服务器发送心跳包,接收客户端的msg,客户端发msg,接收心跳包