欢迎使用CSDN-markdown编辑器
来源:互联网 发布:c语言产生0 1的随机数 编辑:程序博客网 时间:2024/06/04 00:56
网络编程笔记
- 网络编程笔记
- 网络编程基础结构体
- 1. 相关结构体:
- 2. 网络字节序
- 3. 字节操纵函数
- 4. 判断一个文件描述符是不是套接字
- 基本TCP套接字编程
- 1. 相关函数
- 1. socket函数(创建一个套接字)
- 2. connect函数
- 3. bind函数(给套接字绑定地址和端口)
- 4. listen函数(开始在地址上监听相关端口)
- 5. accept函数
- 6. fork和exec
- 7. getsockname和getpeername
- 2.posix 信号处理
- 1. SIGHCLD信号(处理僵尸进程)
- 2.信号集
- 3.信号处理函数signal和sigaction
- 4.SIG_CHLD 信号处理
- 3. 实例 (并发服务器)
- 1. 相关函数
- 网络编程基础结构体
网络编程基础结构体
1. 相关结构体:
- IPv4结构体
struct in_addr{ in_addr_t s_addr; /*32 bit IPV4 address*/}/*头文件<netinet/in.h>*/struct sockaddr_in{ uint8_t sin_len; sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr; char sin_zero[8];}
- 通用ipv4结构体
struct sockaddr{ uint8_t sa_len; sa_family_t sa_family; char sa_data[14];}
- 32位二进制ipv4地址与字符格式的ipv4地址转换函数
//头文件<arpa/inet.h> char * inet_ntoa(struct in_addr in); int inet_aton(const char*cp,struct in_addr *inp); /*下面两个函数已经废弃*/ in_addr_t inet_addr(const char*cp); in_addr_t inet_network(const char*cp); /*下面一对函数即支持ipv4也支持ipv6*/ int inet_pton(int af,const char *src,void *dst); const char * int_ntop(int af,const void *src,char*dst,socklen_t size);
2. 网络字节序
- 计算机内存存储中有两种字节序,大端字节序和小端字节序,将低字节存储在起始位置称为小端,
将高字节存储在起始位置称为大端 - 字节序相关函数
uint16_t htons(uint16_t host16bitvalue); uint32_t htonl(uint32_t host32bitvalue); uint16_t ntohs(uint16_t net16bitvalue); uint32_t ntohl(uint32_4 net32bitvalue);
3. 字节操纵函数
/*第一组起源于4.2bsd*/ //头文件<string.h> void bzero(void * dest,size_t nbytes); void bcopy(const void *src,void *dest,size_t nbytes); //返回0相等,非0不相等 int bcmp(const void *ptr1,const void * ptr2,size_t nbytes); /*第二组ANSI C 提供*/ //头文件<string.h> void * memset(void *dest,size_t len); void * memcpy(void * dest,const void *src,size_t len); int memcmp(const void *ptr1,const void *ptr2,size_t len);
4. 判断一个文件描述符是不是套接字
- 通过fstat获取该文件的st_mode字段并与上S_IFSOCK判断
#include <stdio.h>#include <sys/socket.h>#include <netinet/in.h>#include <sys/stat.h>#include <string.h>#include <arpa/inet.h>int main() { struct sockaddr_in servaddr; bzero(&servaddr,sizeof(servaddr)); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(8090); int fd= socket(AF_INET,SOCK_STREAM,0); struct stat mystat; if(fstat(fd,&mystat)==0){ if(S_ISSOCK(mystat.st_mode)){ printf("is sock"); } } return 0;}
- 通过调用isfdtype函数
//成功返回1,失败返回0int isfdtype(int fd,int fdtype);
基本TCP套接字编程
1. 相关函数
1. socket函数(创建一个套接字)
//非负关键字成功,-1出错#include <sys/socket.h>int socket(int family,int type,int protocol);
2. connect函数
//返回0成功,-1出错#include <sys/socket.h>int connect(int sockfd,const struct sockaddr*servaddr,socklen_t addrlen);
3. bind函数(给套接字绑定地址和端口)
//返回0成功-1出错#include <sys/socket.h>int bind(int sockfd,const struct sockaddr * servaddr,socklen_t addrlen)
4. listen函数(开始在地址上监听相关端口)
//返回0成功-1出错#include <sys/socket.h>int listen(int sockfd,int backlog);
5. accept函数
//返回非负值成功,-1出错#include <sys/socket.h>int accept(int sockfd,struct sockaddr *cliaddr,socklen_t addrlen);
6. fork和exec
#include <unistd.h>//返回值0子进程,>0父进程,-1 出错pid_t fork(void);int execl(const char *pathname,const char * arg0,...)int execv(const char *pathname,char* const argv[])int execle(const char *pathname,const char *arg0,...,NULL,char * const envp[])int execve(cconst char *pathname,char * const argv[],char* const envp[])int execlp(const char * filename,const char *arg0,...)int execvp(const char *filename,char * const argv[])
7. getsockname和getpeername
/** getsockname 用于获取服务器端套接字的信息 getperrname 用于获取客户端套接字的细信息*///返回0成功,-1出错#include <sys/socket.h>int getsockname(int sockfd,struct sockaddr *localaddr,socklen_t * addrlen)int getpeername(int sockfd,struct sockaddr *peeraddr,socklen_t * addrlen)
2.posix 信号处理
1. SIGHCLD信号(处理僵尸进程)
- 在子进程结束时如果父进程未等待它,将产生一个僵尸进程,若在子进程结束时父进程已经结束,则不会产生
僵尸进程,该进程会变成孤儿进程,进而被托管给init。
为了避免产生僵尸进程,占用系统资源,我们需要在父进程中调用wait或waitpid来为子进程收尸。- 当进程正常终止或异常终止时,内核就会向其父进程发送SIGCHLD信号,因为子进程终止是一个异步事件,所
以通知也是异步通知。- 在调用wait和waitpid时进程可能会发生一下集中情况
- 如果所有的子进程都还在运行,则阻塞。
- 如果一个子进程已经终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回
- 如果它没有任何子进程则立即返回错误
- 在服务器变成中我们不能在父进程中调用wait或waitpid函数,因为会造成父进程阻塞。所以我们只能
监听异步信号SIGCHLD
2.信号集
当需要表示多个信号时,就需要信号集了。
信号集类型 sigset_t
//信号集操作函数#include<signal.h>int sigemptyset(sigset_t *set)int sigfiilset(sigset_t * set)int sigaddset(sigset *set,int signo);int sigdelset(sigset_t *set,int signo); //成功返回0,-1出错int sigismember(const sigset_t *set,int signo) //若真返回1,假返回0
3.信号处理函数signal和sigaction
因为signal的语义与函数具体实现有关,所以应该使用sigaction函数代替signal。
一般有一些特殊的信号处理回调函数
+ SIG_IGN 忽略该信号(SIGKILL 和 SIGSTOP 不可以忽略)
+ SIG_DFL 系统默认处理
+ SIG_ERR 错误信号
#include <signal.h>//成功返回0,-1出错void (*signal(int signo,void (*fun)(int))(int)int sigaction(int signo,const struct sigaction * restrict act,struct sigaction * restrict oact)struct sigaction{ void (*sa_handler)(int); //信号处理回调函数 sigset_t sa_mask; //信号掩码,设置阻塞信号。 int sa_flags; void (*sa_sigaction)(int,siginfo_t *,void *);}
sa_flags 的取值
选项 说明 SA_INTERRUPT 由此信号中断的系统调用不自动重启动 SA_NOCLD_STOP 若signo是SIGCHLD时若是作业控制则不产生该信号 SA_NOCLDWAIT 若signo是SIGCHLD时,则当子进程终止时不产生僵尸进程,若调用wait将返回-1,发生ECHCLD错误 SA_NODEFER 当捕捉到该信号时,在执行其信号捕捉函数时,系统不自动阻塞此信号(除非sa_mask设置了该信号) SA_ONSTACK 当用sigaltstack函数已声明一个替换栈,则此信号递送给替换栈上的进程
4.SIG_CHLD 信号处理
当SIG_CHLD信号到达时,应该在signal处理函数中调用wait
或者waitpid避免产生僵尸进程,但是wait存在缺陷,当n个> SIG_CHLD信号同时到达时,可能触发1-n次wait函数,导致
有些子进程成为僵尸进程。
//一个信号处理函数void sid_chld(int signo){ pid_t pid; int stat; while((pid= waitpid(-1,&stat,WNOHANG))>0){ printf("child process %d terminated\n",pid); }}
3. 实例 (并发服务器)
#include <stdio.h>#include <sys/socket.h>#include <arpa/inet.h>#include <unistd.h>#include <string.h>#include <errno.h>int main(int argc, char * argv[]){ int sockfd=0,connfd=0; pid_t pid; struct sockaddr_in servaddr,cliaddr,localaddr,perraddr; bzero(&servaddr,sizeof(servaddr)); bzero(&cliaddr,sizeof(cliaddr)); bzero(&localaddr,sizeof(localaddr)); bzero(&perraddr,sizeof(perraddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(8090); if((sockfd = socket(AF_INET,SOCK_STREAM,0))<0){ printf("socket error,%s",strerror(errno)); _exit(-1); }; socklen_t len = sizeof(servaddr); if(bind(sockfd,(struct sockaddr*)&servaddr,len)<0){ printf("bind error,%s",strerror(errno)); _exit(-1); } if(listen(sockfd,5)<0){ printf("listen error,%s",strerror(errno)); _exit(-1); } len = sizeof(localaddr); if(getsockname(sockfd,(struct sockaddr*)&localaddr,&len)==0){ char buf[16]; bzero(buf,sizeof(buf)); printf("绑定地址%s,绑定端口%d",inet_neta(localaddr.sin_addr.s_addr,buf,sizeof(buf)),ntohs(localaddr.sin_port)); } for(;;){ len = sizeof(cliaddr); if((connfd = accept(sockfd,(struct sockaddr *)&cliaddr,&len))<0){ printf("accept error,%s",strerror(errno)); _exit(-1); } if((pid = fork())==0){ len = sizeof(localaddr); if(getpeername(connfd,(struct sockaddr*)&perraddr,&len)==0){ char buf[16]; bzero(buf,sizeof(buf)); printf("绑定地址%s,绑定端口%d",inet_neta(localaddr.sin_addr.s_addr,buf,sizeof(buf)),ntohs(localaddr.sin_port)); } printf("子进程正在处理链接并执行了ls"); execlp("/bin/ls","ls -al",NULL); }else if(pid <0){ printf("fork error,%s",strerror(errno)); _exit(-1); }else{ close(connfd); } }}
0 0
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 【linux is not Unix】softether服务端安装
- window7(64bit)环境下安装基于TensorFlow后端的Keras 教程
- 查找之折半查找
- JAVA中toString方法的作用
- Hadoop配置
- 欢迎使用CSDN-markdown编辑器
- Linux基础之RAID
- 继承
- 内网和外网
- Sping-AOP:cglib动态代理与JDK动态代理的区别
- 59. Spiral Matrix II
- 数据库原理第一次作业
- Kafka笔记四之存储策略
- Linux下iptables原理