充值网站 模板,阿里巴巴外贸网站论坛,商业类网站,网站广告psd一、网络编程概述1.进程间通信#xff1a;
1#xff09;进程间通信的方式有**#xff1a;管道#xff0c;消息队列#xff0c;共享内存#xff0c;信号#xff0c;信号量这么集中
2#xff09;特点#xff1a;依赖于linux内核#xff0c;基本是通过内核来实现应用层…一、网络编程概述1.进程间通信
1进程间通信的方式有**管道消息队列共享内存信号信号量这么集中
2特点依赖于linux内核基本是通过内核来实现应用层的两个进程间的通信
3缺陷无法多机通讯
2.网络编程
1网络编程适用去不同的pc间的通信可以实现多机运行
2它关心的是地址和数据 地址是指IP地址和端口号。每台PC机连网够都有一个IP地址那么每台联网的PC机可能跑多个服务器然后每个服务器中对应的有很多进程。当客户端接入的时候不知道去对接哪个服务器。那么这时端口号对应的就是每个服务器的端口。客户就可以通过端口号连接到对应的服务器了。
数据是指协议HTTP/TCP/UDP 它是一种数据格式
3.TCP/UDP对比
1TCP面向连接如打电话要先拨号建立连接UDP是无连接的即发送数据之前不需要建立连接
2TCP提供可靠的服务。也就是说通过TCP连接传送的数据无差错不丢失不重复且按序到达UDP尽最大的努力交付即不保证可靠交付
3TCP面向字节流实际上是TCP把数据看成一连串无结构的字节流UDP是面向报文的UDP没用拥塞控制因此网络出现拥塞不会使源主机的发送速率减低对实时应用很有用如IP电话实时视频会议等
4每一条TCP连接只能是点到点的UDP支持一对一一对多多对一和多对多的交互通信
5TCP首部开销字节UDP的首部开销小只有8字节
6TCP的逻辑通信信道是全双工的可靠信道UDP则是不可靠信道
4.端口号的作用
一台拥有IP地址的主机可以提供许多服务比如Web服务FTP服务SMTP服务 这些服务完全可以通过1个IP地址来实现。那么主机是怎样区分不同的网络服务的呢显然不能只靠IP地址因为IP地址和网络服务的关系是一对多的关系。 实际上是通过“IP地址端接口”来区分不同服务的。
端口提供了一种访问通道 服务器一般都是通过知名端口号来识别的。例如对于每个TCP/IP实现来说FTP服务器的TCP端口号都是21每个Telnet服务器的TCP端口号都是23每个TFTP简单文件传送协议服务器的UDP端口号都是69
二、字节序1.定义
字节序是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。
2.常见序
1Little endian小端字节序将低序字节存储在起始地址
LE little-endian
最符合人的思维的字节序
地址低位存储值的低位
地址高位存储值的高位
怎么讲是最符合人的思维的字节序是因为从人的第一观感来说
低位值小就应该放在内存地址小的地方也即内存地址低位
反之高位值就应该放在内存地址大的地方也即内存地址高位
2 Big endian大端字节序将高序字节存储在起始地址
BE big-endian
最直观的字节序
地址低位存储值的高位
地址高位存储值的低位
为什么说直观不要考虑对应关系
只需要把内存地址从左到右按照由低到高的顺序写出
把值按照通常的高位到低位的顺序写出
两者对照一个字节一个字节的填充进去
三、socket编程步骤 1.创建套接字
函数原型
#include sys/types.h /* See NOTES */
#include sys/socket.h
int socket(int domain, int type, int protocol);domain: 指明所使用的协议族通常为AF_INET表示互联网协议族TCP/IP协议族 AF_INET IPv4 因特网域 AF_INET6 IPv6 因特网域 AF_UNIX Uinx 域 AF_ROUTE 路由套接字 AF_KEY 密匙套接字 AF_UNSPEC 未指定
type参数指定socket的类型 SOCK_STREAM 流式套接字提供可靠的面向连接的通信流它使用TCP协议从而保证了数据传输的正确性和顺序性
SOCK_DGRAM 数据报套接字定义了一种无连接的服数据通过相互独立的报文传输是无序了并且不保证是可靠无差错的。它使用数据包协议UDP
SOCK_RAW 允许程序使用底层协议原始套接字允许对底层协议如IP或ICMP进行直接访问功能强大但使用较为不便主要用于一些协议的开发
protocol 通常赋值0 0选择type类型对应的默认协议 IPPROTO_TCP TCP传输协议 IPPROTO_UDP UDP传输协议 IPPROTO_SCTP SCTPC传输协议 IPPROTO_TIPC TIPC传输协议
2.bind()函数IP端口号与相应描述字赋值函数函数原型 #include sys/types.h /* See NOTES */#include sys/socket.hint bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能
用于绑定IP地址和端口号到socketfd
参数 sockfd 是一个socket描述符
addr 是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针指向要绑定给sockfd的协议地址结构这个地址结构根据地址创建socket时的地址协议族的不同而不同addrlen
addr指向的结构体的大小以字节为单位
struct sockaddr *addr一般用替换的 ipv4对应的是
struct sockaddr {sa_family_t sa_family;//协议族char sa_data[14];//IP端口号}同等替换
struct sockaddr_in{sa_family_t sin_family;//协议族in_port_t sin_port;//端口号struct in_addr sin_addr;//IP地址结构体unsigned char sin_zero[8];//填充没用实际意义只是为sockaddr结构在内存中对齐这样两者才能相互转换}地址转换API
//把字符串形式“127.0.0.1”转化为网络能识别的格式
int inet_aton(const char* straddr,struct in_addr *addrp);//把网络格式的IP地址转化为字符串形式
char* inet_ntoa(struct in_addr sin_addr);将主机字节顺序转换为网络字节顺序 网络字节顺序是TCP/IP中规定好的一种数据表示格式它与具体的CPU类型、操作系统等无关从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian排序方式。
为了进行转换 bsd socket提供了转换的函数 有下面四个 htons 把unsigned short类型从主机序转换到网络序 htonl 把unsigned long类型从主机序转换到网络序 ntohs 把unsigned short类型从网络序转换到主机序 ntohl 把unsigned long类型从网络序转换到主机序
在使用little endian的系统中 这些函数会把字节序进行转换 在使用big endian类型的系统中 这些函数会定义成空宏
同样 在网络程序开发时 或是跨平台开发时 也应该注意保证只用一种字节序 不然两方的解释不一样就会产生bug.
htonl()函数 头文件 #include arpa/inet.h htonl()函数 函数原型是uint32_t htonl(uint32_t hostlong) 1.hostlong是主机字节顺序表达的32位数htonl中的h–host主机地址to–to,n–net网络l–unsigned long无符号的长整型(32位的系统是4字节) 2.函数返回值是一个32位的网络字节顺序 3.函数的作用是将一个32位数从主机字节顺序转换成网络字节顺序。htons()函数 函数原型是uint16_t htons(uint16_t hostlong)
1.hostlong是主机字节顺序表达的16位数htons中的h–host主机地址to–to,n–net网络s–short long无符号的短整型(32位的系统是2字节) 2.函数返回值是一个16位的网络字节顺序 3.函数的作用是将一个16位数从主机字节顺序转换成网络字节顺序简单的说就是把一个16位数高低位呼唤。ntohs()函数 函数原型是uint16_t ntohs(uint16_t hostlong)
1.hostlong是网络字节顺序表达的16位数ntohs中的,n–net网络to–toh–host主机地址s–short long有符号的短整型(32位的系统是2字节) 2.函数返回值是一个16位的主机字节顺序 3.函数的作用是将一个16位数由网络字节顺序转换为主机字节顺序简单的说就是把一个16位数高低位互换。ntohl()函数 函数原型是uint32_t ntohs(uint32_t hostlong)
1.hostlong是网络字节顺序表达的32位数ntohs中的,n–net网络to–toh–host主机地址s–unsigned long无符号的短整型(32位的系统是4字节) 2.函数返回值是一个32位的主机字节顺序 3.函数的作用是将一个32位数由网络字节顺序转换为主机字节顺序。大小端 比如: unsigned long hostlong 0xa2b4c6d8;
大端顺序存放 偏移地址 存放内容 0x00000000 0xa2 0x00000001 0xb4 0x00000002 0xc6 0x00000003 0xd8
小端顺序存放 偏移地址 存放内容 0x00000000 0xd8 0x00000001 0xc6 0x00000002 0xb4 0x00000003 0xa2
网络字节顺序一定是大端顺序主机字节不一定 3.监听listen()函数监听设置函数 #include sys/types.h /* See NOTES */#include sys/socket.hint listen(int sockfd, int backlog);
功能 设置能处理的最大连接数listen() 并未开始接收连接只是设置socket 的 listen 模式listen 函数只用于服务端服务器进程不知道要与谁连接因此它不会主动要求与某个进程连接只是一直监听是否有其他客户进程与之连接然后响应该连接请求并对他做出处理一个服务进程可以同时处理多个客户进程的连接。主要就两个功能将一个未连接的套接字转换为一个被动的套接字监听规定内核为相应套接字排队的最大连接数。
内核为任何一个给定监听套接字维护两个队列 未完成连接队列每个这样的SYN 报文段对应其中一项已由某个客户端发出并到达服务器而服务器正在等待完成相应的TCP 三次握手过程。这些套接字处于SYN_REVD 状态
已完成连接队列每个已完成TCP 三次握手过程的客户端对应其中一项。这些套接字处于ESTABLISHED 状态
参数 sockfd sockfd 是socket 系统调用返回的服务器端socket 描述符backlog backlog 指定在请求队列中允许的最大请求数
4.接受连接accept()函数
#include sys/types.h /* See NOTES */
#include sys/socket.hint accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能 accept 函数由TCP 服务器调用用于从已完成连接队列对头返回下一个已完成连接。如果已完成连接队列为空那么进程被投入睡眠。
参数 sockfd sockfd 是socket 系统调用返回的服务器端s_addrsocket 描述符
addr 用来返回已连接的对端客户端的协议地址
addrled客户端大小c_addr
返回值 该函数的返回值是一个新的套接字描述符返回值是表示已连接的套接字描述符而第一个参数是服务器监听套接字描述符。一个服务器通常仅仅创建一个监听套接字它在该服务器的生命周期内一直存在。内核为每个由服务器进程接收的客户连接创建一个已连接套接字表示TCP 三次握手已完成当服务器完成对某个给定客户的服务器时相应的已连接套接字就会被关闭。
5.数据的收发字节流读取函数
在套接字通信中进行字节读取函数read(); write(); 与I/O 中的读取读取函数略有区别因为它们输入或输出的字节数比可能比请求的要少。
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);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);注意这里fd文字描述符就是套接字。。
6.客户端的connect函数connect()函数客户连接主机
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);功能 该函数用于绑定之后的client 端客户端与服务器建立连接
参数 sockfd是目的服务器的socket 描述符 addr是服务器端的IP 地址和端口号的地址结构指针 addrlen地址长度常被设置为sizeof(struct sockaddr)
返回值 成功返回0遇到错误时返回 -1并且error中包含相应的错误码
7.网络消息代码
1.服务器代码
#include stdio.h
#include sys/types.h
#include sys/socket.h
//#include linux/in.h
#include arpa/inet.h
#include netinet/in.h
#include stdlib.h
#include string.hint main()
{int s_fd;char readbuf[128] {0};int nread;char *msg I get your message,QINGYuan is handsome.\n;struct sockaddr_in s_addr;struct sockaddr_in c_addr;memset(s_addr,0,sizeof(struct sockaddr_in));memset(c_addr,0,sizeof(struct sockaddr_in));
//1.sockets_fd socket(AF_INET,SOCK_STREAM,0);if(s_fd -1){perror(socket);exit(-1);
}//2.binds_addr.sin_family AF_INET;s_addr.sin_port htons(8989);inet_aton(192.168.1.71,s_addr.sin_addr);bind(s_fd,(struct sockaddr *)s_addr,sizeof(struct sockaddr_in));//3.listenlisten(s_fd,10);//4.acceptint clen sizeof(struct sockaddr_in);int c_fd accept(s_fd,(struct sockaddr*)c_addr,clen);if(c_fd -1){perror(accept);exit(-1);}printf(start conneting...\n);sleep(2);printf(get connect:%s\n,inet_ntoa(c_addr.sin_addr));//5.readnread read(c_fd,readbuf,128);if(nread -1){perror(read);}else{printf(get message :%d,%s\n,nread,readbuf);
}//6.writeif(write(c_fd,msg,strlen(msg))0){perror(write);exit(-1);
}return 0;}
运行结果 客户端代码:
#include stdio.h
#include sys/types.h
#include sys/socket.h
//#include linux/in.h
#include arpa/inet.h
#include netinet/in.h
#include stdlib.h
#include string.hint main()
{int c_fd;char readbuf[128];int nread;char *msgmsg from client\n;struct sockaddr_in c_addr;memset(c_addr,0,sizeof(struct sockaddr_in));//1.socketc_fdsocket(AF_INET,SOCK_STREAM,0);if(c_fd-1){perror(socket);exit(-1);}//2.connectc_addr.sin_familyAF_INET;c_addr.sin_porthtons(8989);inet_aton(192.168.1.5,c_addr.sin_addr);if(connect(c_fd,(struct sockaddr*)c_addr,sizeof(struct sockaddr))-1){perror(connect);exit(-1);}//3.writewrite(c_fd,msg,strlen(msg));//4.readnreadread(c_fd,readbuf,128);if(nread-1){perror(read);}else{printf(get message from sever:%d,%s\n,nread,readbuf);}return 0;
}
2.多个客户端连接代码
服务器代码
#include stdio.h
#include sys/types.h
#include sys/socket.h
//#include linux/in.h
#include arpa/inet.h
#include netinet/in.h
#include stdlib.h
#include string.hint main(int argc,char **argv)
{int s_fd;char readbuf[128];int nread;int mark0;char msg[128]{0};struct sockaddr_in s_addr;struct sockaddr_in c_addr;if(argc!3){printf(param is not good\n);exit(-1);}memset(s_addr,0,sizeof(struct sockaddr_in));memset(c_addr,0,sizeof(struct sockaddr_in));//1.sockets_fdsocket(AF_INET,SOCK_STREAM,0);if(s_fd-1){perror(socket);exit(-1);}//2.binds_addr.sin_familyAF_INET;s_addr.sin_porthtons(atoi(argv[2]));inet_aton(argv[1],s_addr.sin_addr);bind(s_fd,(struct sockaddr *)s_addr,sizeof(struct sockaddr_in));//3.listenlisten(s_fd,10);//4.acceptint clensizeof(struct sockaddr_in);while(1){int c_fdaccept(s_fd,(struct sockaddr*)c_addr,clen);if(c_fd-1){perror(accept);}printf(connect\n);mark;sleep(2);printf(get connect:%s\n,inet_ntoa(c_addr.sin_addr));if(fork()0){if(fork()0){while(1){memset(msg,0,sizeof(msg));sprintf(msg,welcome No.%d client,mark);//6.writewrite(c_fd,msg,strlen(msg));sleep(3);}}while(1){//5.readmemset(readbuf,0,sizeof(readbuf));nreadread(c_fd,readbuf,128);if(nread-1){perror(read);}else{printf(get message:%d,%s\n,nread,readbuf);}}break;} }return 0;
}客户端代码
#include stdio.h
#include sys/types.h
#include sys/socket.h
//#include linux/in.h
#include arpa/inet.h
#include netinet/in.h
#include stdlib.h
#include string.hint main()
{int s_fd;char readbuf[128] {0};int nread;char *msg I get your message,QINGYuan is handsome.\n;struct sockaddr_in s_addr;struct sockaddr_in c_addr;memset(s_addr,0,sizeof(struct sockaddr_in));memset(c_addr,0,sizeof(struct sockaddr_in));
//1.sockets_fd socket(AF_INET,SOCK_STREAM,0);if(s_fd -1){perror(socket);exit(-1);
}//2.binds_addr.sin_family AF_INET;s_addr.sin_port htons(8989);inet_aton(192.168.1.71,s_addr.sin_addr);bind(s_fd,(struct sockaddr *)s_addr,sizeof(struct sockaddr_in));//3.listenlisten(s_fd,10);//4.acceptint clen sizeof(struct sockaddr_in);int c_fd accept(s_fd,(struct sockaddr*)c_addr,clen);if(c_fd -1){perror(accept);exit(-1);}printf(start conneting...\n);sleep(2);printf(get connect:%s\n,inet_ntoa(c_addr.sin_addr));//5.readnread read(c_fd,readbuf,128);if(nread -1){perror(read);}else{printf(get message :%d,%s\n,nread,readbuf);
}//6.writeif(write(c_fd,msg,strlen(msg))0){perror(write);exit(-1);
}return 0;}结果