网络编程(PPT版)总结版

网络编程(PPT版)

第一章

### 1.普通网络编程程序的框架结构

头文件

定义变量

命令行参数

创建TCP套接口

变量赋值,指定服务器的IP地址和端口

建立与服务器的连接

读服务器的应答并输出到屏幕上

终止程序

2.包裹函数*

作用:包裹函数可以调用实际函数,检查函数返回值,发生错误时终止程序

	int
	Socket(int family, int type, int protocol)
	{
    	 int     n;
	     if ( (n = socket(family, type, protocol)) < 0)
    	     err_sys("socket error");
	    return (n);
	}//举例
//仿写一个
    fun(a,b,c)
    int
    Fun(Eletype a,Eletype b,Eletype c){
    int n;
        if((n==fun(a,b,c))<0)
            err_sys("error!");
        return (n);
	}

3.Unix errno值

全局变量errno在Unix函数发生错误时会被置为一个指示错误类型的正数,函数本身通常返回-1;只在函数发生错误时设置;所有错误都是常值,在头文件(sys/errno.h)中定义,值0不表示任何错

第二章

1.TCP传输协议

首先, TCP 提供客户与服务器的连接(connection)。一个TCP客户建立与一个给定服务器的连接,跨越连接与服务器交换数据,然后终止连接。

其次,TCP提供可靠性。

第三,TCP通过给所发送数据的每一个字节关联一个序列号进行排序。

第四, TCP提供流量控制。

最后,TCP 连接是全双工的。

2.存在time_wait状态的理由

实现终止TCP全双工连接的可靠性

允许老的重复分节在网络中消逝

端口号http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml

套接口对是连接两个端点的四元组:本地IP地址、本地TCP端口号、远程IP地址、远程TCP端口号

套接口是标识每个端点的两个值(IP和port)

第三章

1.IPV4套接口地址结构

struct  in_addr{
	in_addr_t  s_addr;  /* 32位IPv4地址,网络字节序*/
};
struct  sockaddr_in{
	uint8_t  		sin_len;  /*结构体变量长度*/
	sa_family_t		sin_family;  /*AF_INET*/
	in_port	_t		sin_port;  /* 16位端口号*/
	struct  in_addr	 	sin_addr;  
	char			sin_zero[8];  /*保留*/
};

从应用程序开发人员的观点看,通用的套接口地址结构的唯一用途是给指向特定于协议的地址结构的指针转换类型。

2.值-结果参数

1)从进程到内核传递套接口地址结构有3个函数:
bind、connect和sendto
其中一个参数是指向套接口地址结构的指针,另一个参数是结构的大小

2)从内核到进程传递套接口地址结构有4个函数:
accept、recvfrom、getsockname和getpeername
这4 函数的两个参数是:指向套接口地址结构的指针和指向表示结构大小的整数的指针。

为何将结构大小由整数改为指向整数的指针呢?
当函数被调用时,结构大小是一个值(此值告诉内核该结构的大小,使内核在写此结构时不至于越界),当函数返回时,结构大小又是一个结果(它告诉进程,内核在此结构中确切存储了多少信息),这种参数类型叫值—结果参数。

3.字节排序函数

网际协议在处理多字节整数时,使用大端字节序

uint16_t  htons(uint16_t  host16bitvalue);	
uint32_t  htonl(uint32_t  host32bitvalue);
以上两个函数均返回:网络字节序值。

uint16_t  ntohs(uint16_t  net16bitvalue);
uint32_t  ntohl(uint32_t  net32bitvalue);
以上两个函数均返回:主机字节序值。

4.字节操纵函数

#include <strings.h>
void bzero(void *dest,size_t nbytes);
void bcopy(const void * src,void * dest,size_t nbytes);
int bcmp(const void * ptr1,const void * ptr2,size_t nbytes);
返回 0——相等,非0——不相等

#include <string.h>
void * memset(void * dest,int c,size_t len);
void * memcpy(void * dest,const void * src,size_t nbytes);
int  memcmp(const void * ptr1,const void * ptr2,size_t nbytes);
返回: 0——相同
    >0——ptr1所指字节大于ptr2所指字节
    <0——ptr1所指字节小于ptr2所指字节
//功能如其名

5.地址转换函数

#include <arpa/inet.h>
int inet_aton(const char * strptr,struct in_addr * addrptr);
返回:1——串有效,0——串有错
in_addr_t inet_addr(const char * strptr);
返回:若成功,返回32位二进制的网络字节序地址;若有错,则返回 INADDR_NONE (一般为32位均为1的值)
char * inet_ntoa(struct in_addr inaddr);
返回:指向点分十进制数串的指针

INADDR_NONE (一般为32位均为1的值)

#include <arpa/inet.h>
int inet_pton(int family,const char * strptr,void * addrptr);
返回:1——成功,0——输入不是有效的表达格式,-1——出错
const char * inet_ntop(int family,const void * addrptr,char * strptr,size_t len);
返回:指向结果的指针——成功, NULL——出错
(inet_pton函数实现)

struct sockaddr_in addr;
inet_ntop(AF_INET,&addr.sin_addr,str,sizeof(str));

#include "unp.h"
char * sock_ntop(const struct sockaddr *sockaddr,socklen_t addrlen);
返回:非空指针——成功,NULL——出错

sockaddr指向一个长度为addrlen的套接口地址结构。本函数用它自己的静态缓冲区来保存结果,一个指向此缓冲区的指针即为返回值。

(sock_ntop函数实现)

6.readn,writen,readline函数

#include "unp.h"
ssize_t readn(int filedes,void * buff,size_t nbytes);
ssize_t writen(int filedes,const void * buff,size_t nbytes);
ssize_t readline(int filedes,void * buff,size_t maxlen);
均返回:读写字节数,-1——出错

readn,writen,readline函数实现

7.isfdtype函数

测试一个描述字是不是某给定类型。
#include <sys/stat.h>
int isfdtype(int fd,int fdtype);

第四章

### 1.socket函数

#include <sys/socket.h>
int socket(int family, int type, int protocol);
返回:非负描述字——成功,-1——出错

2.connect函数

#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr * servaddr, socklen_t addrlen);
返回:0——成功,-1——出错

客户在调用函数connect前不必非得调用函数bind函数,因为如果必要的话,内核会选择源IP地址和一个临时的端口。

有三个条件可以产生RST:SYN到达某端口但此端口上没有正在监听的服务器;TCP想取消一个已有连接;TCP接收了一个根本不存在的连接上的分节。

3.bind函数

#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr * myaddr, socklen_t addrlen);
返回:0——成功,-1——出错

### 4.listen函数

#include <sys/socket.h>
int listen(int sockfd, int backlog);
返回:0——成功,-1——出错

backlog的值应设为多大呢?

一个方法是假设一个缺省值,但允许设置命令行选项或环境变量来覆盖该缺省值。当指定的值比内核所支持的值要大时,也不受影响,因为内核能把所给的值改为它所支持的最大值且不返回错误。

void Listen(int fd, int backlog)
{	
	char	*ptr;		
	if ( (ptr = getenv("LISTENQ")) != NULL)	
		backlog = atoi(ptr);
	if (listen(fd, backlog) < 0)				
		err_sys(“listen error”);
}

5.accept函数

#include <sys/socket.h>
int accept(int sockfd, struct sockaddr * cliaddr, socklen_t *addrlen);
返回:非负描述字——OK,-1——出错

6.并发服务器

#include <unistd.h>
pid_t  fork (void);
返回:在子进程中为0,在父进程中为子进程ID , -1——出错

7.close函数

#include <unistd.h>
int close(int sockfd);
返回:0——OK, -1——出错

其功能是?

TCP 套接口的close其缺省功能是将套接口做上“已关闭”标记,并立即返回到进程。这个套接口描述字不能再为进程所用:它不能用作为函数read或write 的参数,但TCP将试着发送已排队待发的任何数据,然后按正常的TCP 连接终止序列进行操作。

8.getsockname,getpeername函数

#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t * addrlen);//本地协议地址
int getpeername(int sockfd, struct sockaddr  *peeraddr, socklen_t * addrlen);//远程协议地址
两者均返回:0——OK,-1——出错

9.send,recv函数

#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
返回:读写字节数,-1——出错

第五章

### 1.TCP回射服务器/客户服务器

服务器程序:
Socket,Bind,Listen,Accept,Fork,str_echo,Close
str_echo函数:
Readline,Writen
客户程序:
Socket,Inet_pton,Connect,str_cli
str_cli函数:
Fgets,Writen,Readline,Fputs

2.正常启动与终止的过程

./tcpserv01 &

服务器 socket,bind,listen 阻accept

客户 socket,connect

​ 客户 str_cli 阻fgets

​ 服务器 fork,str_echo->readline 阻read

​ 服务器父 阻accept

​ 客户 EOF(ctrl+d),fgets,str_cli

​ main->exit

​ FIN

​ exit

​ TIME_WAIT

​ SIGCHLD

3.信号的用法

一个进程发往另一个进程(或本身)

由内核发往本身

4.处理SIGCHLD信号

if一个进程终止,且该进程有子进程处于僵尸状态,则所有僵尸进程的父进程ID均置为1(init进程),init进程将作为这些进程的继父并负责清除他们。

调用Listen 之后,增加函数调用:
Signal (SIGCHLD , sig_chld ) ;

EOF FIN

子进程 readline

父进程 阻accept sig_chld->wait

内核使accept返回一个EINTR错误

### 5.wait,waitpid函数*

#include <sys/wait.h>
pid_t wait(int * statloc);
pid_t waitpid(pid_t pid,int * statloc,int options);
返回:进程ID——成功(waitpid返回有可能为0);-1——出错

参数常用WNOHANG,它通知内核在没有已终止子进程时不要阻塞。

缺省行为指默认行为

6.程序运行异常

  1. accept返回前连接夭折
  2. 服务器进程终止
  3. SIGPIPE信号
  4. 服务器主机崩溃
  5. 服务器主机崩溃后重启
  6. 服务器主机关机

7.数据格式

方法一 在客户与服务器之间传递文本串
方法二 在客户与服务器端传递二进制结构

结构体:memcpy()函数;snprintf函数;序列化方法

TCP端口号 IP地址

R (TASK_RUNNING),可执行状态;
S (TASK_INTERRUPTIBLE),可中断的睡眠状态;
D (TASK_UNINTERRUPTIBLE),不可中断的睡眠状态;
T (TASK_STOPPED or TASK_TRACED),暂停状态或跟踪状态;
Z (TASK_DEAD - EXIT_ZOMBIE),退出状态,进程成为僵尸进程。
拓展

第六章

1.IO复用?

如果一个或多个I/O条件满足(例如,输入已准备好被读,或者描述字可以承接更多的输出)时,我们就被通知到。这个能力被称为I/O复用

一个输入操作一般有两个阶段

1)等待数据准备好

2)从内核到进程拷贝数据

2.select函数(I/O复用)

这个函数允许进程指示内核等待多个事件中的任一个发生,并仅在一个或多个事件发生或经过某指定的时间后才唤醒进程。

#include <sys/select.h>
#include <sys/time.h>
int select(int maxfdp1,fd_set * readset,fd_set * writeset,fd_set * exceptset,const struct timeval * timeout);
返回:准备好描述字的总数目。0——超时,-1——出错

struct timeval {
	long tv_sec;
	long tv_usec; //微秒,1微秒等于百万分之一秒
};

void FD_ZERO(fd_set * fdset);
void FD_SET(int fd , fd_set * fdset);
void FD_CLR(int fd , fd_set * fdset);
int FD_ISSET(int fd , fd_set * fdset);

如果我们对某个条件不感兴趣,函数select的三个中间参数readset、 writeset 和exceptset中相应参数就可设为空指针。

3.shutdown与close函数

1) close将描述字的访问计数减1,仅在此计数为0时才关闭套接口。用shutdown我们可以激发TCP的正常连接终止序列,而不管访问计数。
2)close终止了数据传送的两个方向:读和写。shutdown可以只关闭读或写,也可以两个都关闭。

#include <sys/socket.h>
int shutdown(int sockfd , int howto);
返回: 0——成功,-1——出错

4.简述DDOS

如果一个恶意客户连接到服务器上,**发送一个字节的数据(而不是一行数据)后就睡眠。**服务器将调用readline,它从客户上读到单个字节的数据,然后就阻塞于下一个read调用以等待此客户的其他数据。

5.pselect函数

#include <sys/select.h>
#include <signal.h>
#include <time.h>
int pselect(int maxfdp1, fd_set * readset, fd_set * writeset, fd_set * exceptset, const struct timespec * timeout, const sygset_t * sigmask);

struct  timespec
{
	time_t tv_sec;
	long tv_nsec;  // 1纳秒=10-9秒
};

函数pselect增加了第六个参数:指向信号掩码的指针。**这允许程序禁止递交某些信号,**测试由这些当前禁止的信号的信号处理程序所设置的全局变量,然后调用pselect,告诉它临时重置信号掩码。

6.poll函数

#include <poll.h>
int poll(struct pollfd * fdarray, unsigned long nfds, int timeout);
返回:准备好描述字的个数,0——超时,-1——出错 
struct pollfd
{
	int fd;
	short  events;//状态
	short  revents;//异常类型
}; 

7.epoll函数

#include <sys/epoll.h>
int epoll_create(int size);
//创建内核事件表。

epoll与poll,select差异

首先,epoll使用一组函数完成任务,而不是单个函数;
其次,epoll把用户关心的文件描述符上的事件放在内核里的一个事件表中,从而无须像select和poll那样每次调用都要重复传入文件描述符集或事件集。

#include <sys/epoll.h>
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
//操作epoll的内核事件表。

#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
//epoll系列系统调用的主要接口,它在一段时间内等待一组文件描述符上的事件。
//成功:返回就绪的文件描述符的个数,-1出错并设置errno

LT和ET模式

第七章

getsockopt,setsocketopt函数

#include <sys/socket.h>
int getsockopt(int sockfd,int level,int optname,void *optval,socklen_t *optlen);
int setsockopt(int sockfd,int level,int optname,void *optval,socklen_t *optlen);
返回:0——OK,-1——出错

第八章

1.recvfrom,sendto函数

#include <sys/socket.h>
ssize_t  recvfrom(int sockfd, void * buff, size_t nbytes, int flags, struct sockaddr * from, socklen_t * addrlen);

ssize_t  sendto(int sockfd, const void * buff, size_t  nbytes, int flags, const struct  sockaddr * to, socklen_t  addrlen);
		两者均返回:读写字节——成功,-1——出错

2.UDP回射程序

用自己的话说,类似TCP,writen变成sendto,readline变成recvfrom

3.程序运行异常

  1. 数据报的丢失
  2. 验证接收到的响应
  3. 服务器进程未运行

4.UDP的connect函数

给UDP套接口调用connect,与TCP连接毫不相同:**没有三路握手过程。内核只是记录对方的IP地址和端口号,**它们包含在传递给connect的套接口地址结构中,并立即返回给调用进程。

5.再次调用的目的

给一个UDP套接口多次调用connect。对于已连接UDP套接口,进程可给那个套接口再次调用connect以达到下面两个目的之一:
1)指定新的IP地址和端口号;
2)断开套接口。 (设置套接口地址结构的地址族(为AF_UNSPEC)

第九章

1.小点

gethostbyname和gethostbyaddr在主机名字与IP地址间进行转换;

getservbyname和getservbyport在服务名字和端口号间进行转换。

2.gethostbyname函数

#include <netdb.h>
struct hostent * gethostbyname(const char *hostname);
返回:非空指针——成功,空指针——出错,同时设置h_errno

struct  hostent
{
	char  * h_name;//主机名\0
	char  **h_aliases;//别名\0
	int  h_addrtype;//AF_INET
	int  h_length;//4
	char  **h_addr_list;//IP
};
#define h_addr  h_addr_list[0]

3.gethostbyname2函数

#include <netdb.h>
struct hostent * gethostbyname2(const  char *hostname, int family);
返回:非空指针——成功,空指针——出错,同时设置h_errno

4.gethostbyaddr函数

#include <netdb.h>
struct  hostent * gethostbyaddr(const char *addr, size_t len, int family);
返回:非空指针——成功,空指针——出错,同时设置h_errno

5.uname,gethostname函数

函数uname返回当前主机的名字。它不是解析器库中的一部分,经常与函数gethostbyname一起用来确定本地主机的IP地址。

#include <sys/utsname.h>
int uname(struct utsname * name);
返回:非负值——成功,-1——出错

函数gethostname也返回当前主机的名字。
#include <unistd.h>
int gethostname(char * name,size_t namelen);
返回:0——成功,-1——出错

6.getservbyname,getservbyport函数

#include <netdb.h>
struct servent * getservbyname(const char *servname, const char * protoname);
返回:非空指针——成功,空指针——出错
    
struct servent
{
	char * s_name;
	char ** s_aliases;
	int s_port;
	char * s_proto;
};

函数getservbyport在给定端口号和可选协议后查找相应的服务。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值