3. 网络编程

1. 接口

socket( , , )返回一个int端口

  • 调用connect read就是client;
  • 调用bind,listen,accept就是server
1.2 基于linux的文件操作

linux里面认为socket也是文件的一种,所以调用的是read, write
但是windows里区分socket和文件,所以它用的是recv, send

文件描述符:是系统分配给文件或套接字的整数(int),但是标准输入,标准输出,标准错误是三个输入输出对象,程序一开始就自动分配文件描述符了的就(一般编号就是0,1,2)。文件描述符可以理解为映射号。

1.3 基于windows的实现

windows下适用socket如下条件:
1.头文件:winsock2.h
2.链接库:ws2_32.lib
3.定义WSADATA结构体,
3.初始化:WASstartup()设置winsock版本(可用MAKEWORD函数),出入WSADATA结构体;

WSADATA wsaData;
...
if(WSAStartup(MAKEWORD(2,2), &wsaData)!=0)
	ErrorHandling("WSAStartup() error");
...
WSACleanup(void);

接口差异:
(功能差不多,具体有差别)

  • close -> closesocket
  • write -> send
  • read -> recv
2.套接字类型及协议
2.1协议

socket(协议族,套接字类型,

3.地址族与数据序列

一些计算机网络的基础知识。

  • 操作系统由端口号区分不同套接字
  • 地址信息的表示:
ipv4地址结构体:
地址族;ip地址;端口号;
struct sockaddr_in{
	sa_family_t sa_family; // 地址族
	uint_16t sin_port; //端口号
	struct in_addr sin_addr; // ip结构体
	char sin_zero[8];	
}
#define uint32_t In_addr_t;
struct in_addr{
	In_addr_t s_addr;
}

  • cpu解析数据的方式2种:

    • 大端序:数据高字节存放到内存低字节
    • 小端序:低字节存放到低字节
      intel以小端序存数据。
      但是约定网络传输数据以大端序传。
  • 转换字节序的函数:htons(把short型数据从host主机字节序转化to为网络字节序n)

  • inet_addr能自动解析ip地址,赋值就行

  • inet_aton 直接返回修改addr_in结构体

  • inet_ntoa 把网络字节序整数转为ip字符串

  • INADDR_ANY 自动获取服务端ip地址

4.基于TCP的服务端

listen(socket1, c) c是等待队列大小
如何实现非阻塞的accpet?

5.TCP的服务/客户端

server给client传数据,可能数据长度会大于缓存窗口嘛?
不会,因为TCP有流量控制功能,窗口控制。
TCP数据传输没有边界:数据传输过程中调用的I/O次数不具有意义

6.UDP服务/客户端

UDP有数据边界:sendto和recvfrom的次数要完全一致才不会丢包。

udp 的client流程:

  • 向udp的socket注册目标ip的端口号;
  • sendto传数据;
  • 删除socket中注册的目标地址信息;

udp的client sock直接sendto就是没连接的udp
若多次udp传输,可以建立连接的udp,向sock注册ip和端口,后面不仅可以sendto,

7. 断开套接字

close和closesocket是完全断开连接。
半关闭:只接不发,或者只发不接

8.域名

DNS:是ip地址和域名相互转换的系统 domain name system

域名相当于虚拟地址,dns把它转化为地址
内置dns服务器-> DNS服务器->根DNS服务器

gethostbyname

  • 由域名字获取ip地址
    gethostbyaddr
9.套接字多种可选项

getsockopt:获取套接字种类信息
setsockopt:设置套接字属性
SO_REUSEADDR属性
TCP-NODELAY属性

  • nagle算法:最大限度的缓冲,收到ACK后就发送;
  • 不用nagle就是流水线传输,速度快,大文件可考虑禁用;
  • 设TCP_NODELAY为1
10. 多进程服务器

并发服务器实现模型:

  • 多进程服务器
  • 多路复用服务器
  • 多线程服务器
多进程服务器

多进程:“占用内存空间正在运行的程序”;
进程ID:

  • id>=2

  • ps查看正在运行所有线程

  • fork创建进程 子进程调fork返回0,

  • 僵尸进程:

  • wait

    • pid_t wait(int *statloc)
    • statloc: WIFEXITED 子进程正常终止时返回,WEXISTSTATUS返回子进程的返回值
  • waitpid

    • pid_t waitpid(pid_t pid, int *statloc, int options)
    • pid为-1则等待任意进程终止
    • statloc:同上
    • options:传WNOHANG表没终止的子进程在此不阻塞而是返回0退出;
    • 返回终止的进程号

信号:signal

  • 注册信号
  • alarm会产生SIGNALRM信号
  • ctrl+c产生SIGINT信号

sigaction:

  • 类似signal
  • 稳定
  • 在不同UNIX系统中完全相同,signal可能不同
    socket属于操作系统的资源,不属于进程
11.进程间通信
  • 管道pipe
    • [0]:出口
    • [1]:入口
    • 通过fork传递到子进程中
12.I/O复用

accpet/recv是阻塞的,有客户端连接上来才会继续往下执行(如果是多个客户端都链接上来,listen时有监听队列池,可以挨个处理),
select使用
1.设置文件描述符
fd_set结构体,数组,每位存0/1,1表示是监视对象,具体是通过位为单位进行的。
- FD_ZERO:全部位初始化0
- FD_SET:FD_SET(int fd, fd_set* fdset) 向fdset注册fd的信息
- FD_CLR:清除某一位的fd信息
- FD_ISSET:检查某一位是否被监视
2.设置监视范围
int select(int maxfd, fd_set* readset, fd_set* writeset, fd_set* exceptset, const struct timeval* timeout);
在区间范围内监视文件描述符的三种状态:

  • 是否存在待读取数据
  • 是否可传输无阻塞数据
  • 是否异常
    3.设置超时
    struct timeval{
    long tv_sec;
    long tv_usec;
    }
    4.调用select函数查看结果
    除了发生变化的位外,fd_set别的位都要归0。
13.其他IO函数

1. send、recv
关于最后的flags位设置:

  • MSG_DONTWAIT: 非阻塞IO
  • MSG_WAITALL:
  • MSG_DONTROUTE:
  • MSG_PEEK:
  • MSG_OOB
    • 发送紧急消息

关于OOB
tcp的oob并不是通过完全不同的通信路径传输数据实现的,而是由tcp里面的紧急模式标识设置传输的。
并不保证数据的迅速传输,但是通过及时处理信号的方式实现对紧急数据的及时处理。

2. readv writev
对数据整合一起传输以及发送
减少write,read次数

14.广播和多播

1.多播

  • 基于udp
  • 借助路由器,复制UDP数据包传递到多个主机,不向同一片区域发送多个数据包
  • 不像tcp建立多个连接传多次,不像udp传多次
  • 只发送一次数据,组内客户端都会接收到数据
  • 多播组数在IP范围内可任意增加
  • 多播组D类IP地址: 224.0.0.0~239.255.255.255
  • 不支持多播的路由器,使用隧道技术(Tunneling)
  1. TTL( time to live)
    设置: setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (void*)&itime_live, sizeof(itime_live));
    IPPROTO_IP是协议,黑体是关键字

3.加入多播
结构体,设置成员变量,再通过setsockopt导入设置;
struct ip_mreq join_addr;
join_addr.imr_multiaddr.s_addr = "多播组地址信息“;
join_addr.imr_interface.s_addr = "加入多播组的主机地址信息”;
setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*)& join_addr, sizeof(join_addr));

3.广播
区域网内
也是由setsockopt完成

15. 标准I/O

缓冲带给数据传输带来提升。

  • 数据包更高效
  • 数据向输出缓冲移动的次数
    例如复制文件,利用系统函数read, write比fgets, fputs慢。

标准I/O函数缺点:

  • 不容易双向通信;
  • 可能频繁调用fflush函数;强迫将缓冲区数据输出
  • 要以FILE结构体指针接收文件描述符;

int -> FILE* : fdopen
FILE* -> int : fileno

16.I/O流分离

此前也有过io的流分离,如TCP/IP的半关闭(shutdown(dock, SHUT_WR) )和fdopen对sock的读写分离
优点:

  • 分离输入输出降低实现难度;
  • 与输入无关的输入操作可以提高速度;
  • 区分IO缓冲提高缓冲性能;
    fcntl:更改文件描述符属性;
    如何实现fdopen后的半关闭?
  • 复制文件描述符
    dup(fd)
    dup2(fd, i)
17. epoll

select的速度慢

  • 对所有文件描述符都要循环检查;
  • 每次调用都要传递监视对象信息;
    尤其是第二点更影响速度,第一点可以代码优化掉,第二点传递监视对象进select,就是想操作系统传递监视对象信息,难以优化。

select优点:

  • 大部分系统都支持select;
  • 在接入量少,需要兼容性时都应考虑select;

epoll

  • epoll_create: 创建epoll例程(类似socket描述符)
  • epoll_ctl: 向epoll注册监视文件描述符
    • 有很多类型事件
    • struct epoll_event
    • union epoll_data
  • epoll_wait: 监听等待
    在长连接且频繁发送大小不一的消息时,epoll和IOCP模型性能好。
    条件触发-边缘触发
  • 边缘触发可以分离接收数据和处理数据的时间点;
    • 如果用条件触发方式延迟接收处理数据以求时间一致,会导致epoll_wait的事件累计
  • epoll默认条件触发
18.多线程服务器

解决多进程的开销、效率问题。多进程的上下文切换开销大,线程创建更快。

pthread_create() 创建
pthread_join() 接收返回

编译: -lpthread
线程安全:

  • linux: _r win: _s
  • #define _REENTRANT
  • 编译加参数 -D_REENTRANT

线程同步
mutex

  • pthread_mutex_t
  • pthread_mutex_init
  • pthread_mutex_lock;
  • pthread_mutex_unlock;
    关于临界区的保护范围,大还是小,根据情况判断。

信号量
sem_t
sem_init
sem_destory
sem_post 信号量加1
sem_wait 信号量减1
利用类似引用计数的方式来标记资源的更新与请求。所以信号量本身是不是原子的(是),应该可以用atomic_flag/atomic_bool代替么?

线程销毁

  • pthread_join: 让主线程阻塞等待子线程
  • pthread_detach: 分离线程
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值