当前位置: 首页 > news >正文

内容型网站互联网广告推广

内容型网站,互联网广告推广,广州荔湾做网站,淘客联盟如何做网站推广一.网络准备 1.套接字 在TCP/IP 协议中,“ip 地址TCP 或UDP 端口号”唯一标识网络通讯中的一个进程。“IP 地址端口号”就对应一个socket。欲建立连接的两个进程各自有一个 socket 来标识,那么这两个 socket 组成的 socket pair 就唯一标识一个连接。因…

一.网络准备

1.套接字

TCP/IP 协议中,“ip 地址+TCP 或UDP 端口号”唯一标识网络通讯中的一个进程。“IP 地址+端口号”就对应一个socket。欲建立连接的两个进程各自有一个 socket 来标识,那么这两个 socket 组成的 socket pair 就唯一标识一个连接。因此可以用 socket 来描述网络连接的一对一关系。

在这里插入图片描述

简单来说,用数学里面的坐标系类比一下,(IP地址,端口号)表示一个进程即一个套接字,两个套接字连线表示通信。

  • 一个文件描述符指向一个套接字(该套接字内部由内核借助两个缓冲区实现)。
  • 在通信过程中, 套接字一定是成对出现的。

2.网络字节序列

计算机(主机)对于多字节序列采用的是小端法存储,而网络通信的多字节序列是大端法存储的,因此在进行网络通信时,主机把数据送到客户端的发送缓冲区前需要把数据进行网络字节转换,同样的接受主机在服务器的接收端取出数据后,又要把数据转化成主机字节序列。

#include <arpa/inet.h>uint32_t htonl(uint32_t hostlong);                    //本地---》网络(IP地址)
uint16_t htons(uint16_t hostshort);                   //本地---》网络(端口)
uint32_t ntohl(uint32_t netlong);                     //网络---》本地(IP地址)
uint16_t ntohs(uint16_t netshort);                    //网络---》本地(端口)

解释:

  • h表示本地主机(host)
  • to表示变换
  • n表示网络(net)
  • l表示IP地址(IP地址用32位表示)
  • s表示端口

注意:我们平时用点分十进制表示IP地址,所以要想进行网络字节转换,先要使用atoistring转化成int

3.IP地址转换函数

为了直接从点分十进制进行转化成网络字节序,所以有了IP地址转换函数。

#include <arpa/inet.h>int inet_pton(int af, const char *src, void *dst);                               //IP地址---》网络

解释:

  • af:表示版本协议号,只能取AF_INET表示IPv4或AF_INET6表示IPv6
  • src:传入的IP地址(点分十进制,string类型)
  • dst:传出的转换后的IP地址(网络字节序)
  • 返回值:1表示成功;0表示异常,说明传入的src不是一个IP地址;-1表示失败
#include <arpa/inet.h>const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);       //网络---》IP地址

解释:

  • src:传入的转换后的IP地址(网络字节序)
  • dst:传出的IP地址(点分十进制,string类型)
  • size:dst缓冲区的大小
  • 返回值:成功返回dst,失败返回NULL

4.sockaddr数据结构

直接说结论:后面的bind()函数的参数要用到strcut sockaddr这种结构体的指针,但是现在IPv4使用的结构体普遍是strcut sockaddr_in,所以现在的使用方式是我们一般先定义strcut sockaddr_in的结构体,使用的时候进行强转。比如:

struct sockaddr_in servaddr;
bind(listen_fd, (struct sockaddr *)&servaddr, sizeof(servaddr));	

其余不要管,重点看bind()的第二个参数。

所以,现在我们重点学习一下strcut sockaddr_in结构体:

struct sockaddr_in {__kernel_sa_family_t sin_family; 			  	//地址结构类型__be16 sin_port;					 		  //端口号(网络字节序)struct in_addr sin_addr;					   //IP地址(网络字节序)
};struct in_addr {						__be32 s_addr;                                  //IP地址(网络字节序)
};

注意:这里的sockaddr_in的第三个参数是一个结构体的形式,所以赋值时需要注意,例如:

struct sockaddr_in addr;
addr.sin_family = AF_INET/AF_INET6;
addr.sin_port = htons(9527);
int dst;
inet_pton(AF_INET,"192.157.22.45",(void *)&dst);
addr.sin_addr.s_addr = dst;

这里使用强转把dst变成void *类型,赋值是不要忘了.s_addr进入对应结构体内部赋值。

一般的时候,我们用的是本地主机写代码,所以可以将:

int dst;
inet_pton(AF_INET,"192.157.22.45",(void *)&dst);
addr.sin_addr.s_addr = dst;

写成

addr.sin_addr.s_addr = htonl(INADDR_ANY);

这里的INADDR_ANY是一种宏,表示取出系统中有效的任意IP地址,但是是二进制类型。

二.网络套接字函数

1.socket模型

在这里插入图片描述

  • socket():创建套接字
  • bind():绑定服务器的IP和端口
  • listen():设置同时监听上限
  • accept():阻塞监听客户端连接
  • connect():客户端绑定IP和端口,进行连接

注意,在一个模型中其实有三个socket套接字,其中服务器刚开始的套接字在accept()函数里作为参数传入,返回另一个套接字来与客户端进行真正的连接。

2.socket函数

函数原型:

#include <sys/socket.h>int socket(int domain, int type, int protocol);
  • domain:用来指定传输协议,AF_INETAF_INET6AF_UNIX(表示本地协议,使用在Unix和Linux系统上,一般都是当客户端和服务器在同一台及其上的时候使用)
  • type:用来指定协议类型,可以取SOCK_STREAM表示流式协议或SOCK_DGRAM表示报式协议
  • protocol:传0表示默认协议

type为SOCK_STREAM且protocol=0表示使用TCP传输,type为SOCK_DGRAM且protocol=0表示使用UDP传输。

3.bind函数

作用:给socket绑定一个地址结构(IP地址+端口)

#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfdsocket文件描述符,一般取上面socket()函数的返回值
  • *addr:上面介绍过,用来指定地址结构信息
  • addrlen:地址结构大小,总是取sizeof(addr)

4.listen函数

作用:设置同时与服务器建立连接的客户端数量

#include <sys/socket.h>int listen(int sockfd, int backlog);
  • sockfd:socket文件描述符,一般取上面socket()函数的返回值
  • backlog:连接上限,最大为128

5.accept函数

作用:阻塞等待客户端连接,成功的话,返回一个成功与客户端连接的socket文件描述符

#include <sys/socket.h>int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • sockdf: socket文件描述符,一般取上面socket()函数的返回值,相当于把开始的socket传入
  • addr:传出参数,返回成功链接客户端地址信息,含IP地址和端口号
  • addrlen:传入传出参数(值-结果),传入sizeof(addr)大小,函数返回时返回真正接收到地址结构体的大小
  • 返回值: 成功返回一个新的socket文件描述符,用于和客户端通信,失败返回-1,设置errno

6.connect函数

作用:使用现有的socket与服务器建立连接

#include <sys/socket.h>int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfdsocket文件描述符,一般取上面socket()函数的返回值
  • *addr:服务器的地址结构,用来连接
  • addrlen:地址结构大小,总是取sizeof(addr)

7.read函数

read函数用于从socket中读取数据。它的原型如下:

ssize_t read(int fd, void *buffer, size_t count);
  • fd:是socket的文件描述符,用于标识一个打开的socket。
  • buffer:是一个指针,指向一个缓冲区,该缓冲区用于存储从socket读取的数据。
  • count:指定了buffer的大小,即希望读取的最大字节数。

read函数返回实际读取的字节数。如果read返回0,表示连接已经关闭。如果返回-1,表示发生了错误,此时可以通过errno变量查看错误类型。

8.write函数

write函数用于向socket写入数据。它的原型如下:

ssize_t write(int fd, const void *buffer, size_t count);
  • fd:同样是socket的文件描述符。
  • buffer:是一个指针,指向包含要发送数据的缓冲区。
  • count:指定了要发送的字节数。
  • write函数返回实际写入的字节数。如果返回-1,表示发生了错误,同样可以通过errno变量查看错误类型。

8.文件描述符

fd_set 是一个数据类型,用于在 select 系统调用中表示一组文件描述符。以下是与 fd_set 相关的一些常用宏函数,它们用于操作 fd_set:

  • FD_ZERO:
    作用:将 fd_set 清零,即初始化 fd_set,使其不包含任何文件描述符。
    使用方法:FD_ZERO(&fdset);
  • FD_SET:
    作用:将一个文件描述符添加到 fd_set 中。
    使用方法:FD_SET(fd, &fdset); 其中 fd 是要添加的文件描述符,fdset 是 fd_set 的实例。
  • FD_CLR:
    作用:从 fd_set 中移除一个文件描述符。
    使用方法:FD_CLR(fd, &fdset); 其中 fd 是要移除的文件描述符,fdset 是 fd_set 的实例。
  • FD_ISSET:
    作用:测试一个文件描述符是否在 fd_set 中。
    使用方法:FD_ISSET(fd, &fdset); 如果 fd 在 fdset 中,则返回非零值;否则返回0。

三.实现一个简单的通信

1.通信流程分析

TCP通信流程分析:

	server:1. socket()	创建socket
​		2. bind()	绑定服务器地址结构
​		3. listen()	设置监听上限
​		4. accept()	阻塞监听客户端连接
​		5. read(fd)	读socket获取客户端数据
​		6.--大写	toupper()7. write(fd)8. close();​	client:1. socket()	创建socket
​		2. connect();	与服务器建立连接
​		3. write()	写数据到 socket
​		4. read()	读转换后的数据。
​		5. 显示读取结果
​		6. close()

2.实现服务器

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>#define ser_port 9527
int main()
{//1.socket partint sfd=0,cfd=0;sfd = socket(AF_INET, SOCK_STREAM, 0);if(sfd==-1){printf("socket error\n");}//2.bind partstruct sockaddr_in ser_addr,cet_addr;ser_addr.sin_family=AF_INET;ser_addr.sin_port=htons(ser_port);ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);bind(sfd, (struct sockaddr *)&ser_addr, sizeof(ser_addr));//3.listen partlisten(sfd,20);//4.accept partchar client_ip[BUFSIZ];socklen_t cet_addr_len = sizeof(cet_addr);cfd = accept(sfd,(struct sockaddr *)&cet_addr,&cet_addr_len);if(cfd==-1){printf("accept socket error\n");}//5.read partchar buf[BUFSIZ];while(true){int ret = read(cfd,buf,sizeof(buf));write(STDOUT_FILENO,buf,ret);for(int i=0;i<ret;i++){buf[i]=toupper(buf[i]);}write(cfd,buf,ret);}//6.close partclose(sfd);close(cfd);return 0;
}

3.实现客户端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>#define ser_port 9527
int main() {//1.socket partint hfd=0;hfd=socket(AF_INET, SOCK_STREAM, 0);if(hfd==-1){printf("socket error\n");}//2.connect partstruct sockaddr_in cil_addr;cil_addr.sin_family=AF_INET;cil_addr.sin_port=htons(ser_port);inet_pton(AF_INET,"192.168.242.128",&cil_addr.sin_addr.s_addr);connect(hfd,(struct sockaddr *)&cil_addr,sizeof(cil_addr));// 3. Write and Read partchar buf[BUFSIZ];int count = 10;while (count-- > 0) {if (write(hfd, "hello", 5) == -1) {perror("write");close(hfd);exit(EXIT_FAILURE);}int ret = read(hfd, buf, sizeof(buf));if (ret == -1) {perror("read");close(hfd);exit(EXIT_FAILURE);} else if (ret == 0) {printf("Server disconnected\n");break;}write(STDOUT_FILENO, buf, ret);}close(hfd);return 0;
}

四.出错封装函数思想

1.封装思想

上面简单的写了一个实现大小写转换的通信服务器和客户端,但是并不完善,里面的很多函数调用都没有做错误处理,在实际编写过程中并不规范。

我们以accept()函数为例,在上面的例子中,我们是这样写的:

    char client_ip[BUFSIZ];socklen_t cet_addr_len = sizeof(cet_addr);cfd = accept(sfd,(struct sockaddr *)&cet_addr,&cet_addr_len);if(cfd==-1){printf("accept socket error\n");}

但是实际过程中的main.cpp代码量其实是很少的,我们可以把accept()函数进行封装成类似自定义函数,存储在另一个源文件中,这样就可以在main.cpp调用自定义的Accept()函数啦。

一般这种错误函数的封装,我们把重新自定义的函数名取为原函数名基础上首字母大写,然后在自定义函数内部实现错误封装,所以上述代码可以改成:

int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{int n;again:if ( (n = accept(fd, sa, salenptr)) < 0) {if ((errno == ECONNABORTED) || (errno == EINTR))goto again;elseperr_exit("accept error");}return n;
}

注意:自定义函数封装在wrcp.cpp文件中,不要忘了对应的wrcp.h头文件。

2.读写函数

我们在C语言文件操作时,学习了一些读写函数,但是强调过只有read()write()是满足系统调用的(即在socket通信过程中使用),所以平时的读写我们要自定义一些读(写)n字节函数或读(写)n行函数。下面代码仅供参考:

ssize_t Readn(int fd, void *vptr, size_t n)
{size_t nleft;ssize_t nread;char *ptr;ptr = vptr;nleft = n;while (nleft > 0) {if ( (nread = read(fd, ptr, nleft)) < 0) {if (errno == EINTR)nread = 0;elsereturn -1;} else if (nread == 0)break;nleft -= nread;ptr += nread;}return n - nleft;
}ssize_t Writen(int fd, const void *vptr, size_t n)
{size_t nleft;ssize_t nwritten;const char *ptr;ptr = vptr;nleft = n;while (nleft > 0) {if ( (nwritten = write(fd, ptr, nleft)) <= 0) {if (nwritten < 0 && errno == EINTR)nwritten = 0;elsereturn -1;}nleft -= nwritten;ptr += nwritten;}return n;
}static ssize_t my_read(int fd, char *ptr)
{static int read_cnt;static char *read_ptr;static char read_buf[100];if (read_cnt <= 0) {
again:if ((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {if (errno == EINTR)goto again;return -1;	} else if (read_cnt == 0)return 0;read_ptr = read_buf;}read_cnt--;*ptr = *read_ptr++;return 1;
}ssize_t Readline(int fd, void *vptr, size_t maxlen)
{ssize_t n, rc;char c, *ptr;ptr = vptr;for (n = 1; n < maxlen; n++) {if ( (rc = my_read(fd, &c)) == 1) {*ptr++ = c;if (c == '\n')break;} else if (rc == 0) {*ptr = 0;return n - 1;} elsereturn -1;}*ptr = 0;return n;
}
http://www.khdw.cn/news/10712.html

相关文章:

  • 网页个人简历模板上海优化seo
  • 包头住房和城乡建设委会会网站专门代写平台
  • 淘宝网站做多久国内最新新闻事件今天
  • 网站制作字怎么放在图上面如何做网站推广
  • 有个人做网站的山西免费网站关键词优化排名
  • 初二做网站的首页模板中文域名查询官网
  • 探测网站是什么程序做的成都网站排名优化公司
  • 网站维护中 html怎么从网上找客户
  • 外贸网站建设价格怎么样合肥网络公司
  • 案例较少如何做设计公司网站域名网
  • 做网站怎么接业务不死鸟分享友情链接
  • 惠州网站建设选惠州邦网络宣传渠道
  • 住建网官网seo的收费标准
  • 做网站的绿色背景图关键词挖掘机爱站网
  • 给非吸公司建设网站免费合作推广
  • 电商网站功能模块图武汉seo优化代理
  • wordpress用户管理官网整站优化
  • 电子商务网站建设期末作业商家推广平台有哪些
  • APP网站怎么做大型网站建设平台
  • 石狮住房和城乡建设局网站泰安百度推广电话
  • 网站网络推广教程在哪里找专业推广团队
  • 做一个大型网站北大青鸟培训机构靠谱吗
  • 做英文网站seo搜索引擎优化心得体会
  • 贵阳网站开发公司推荐疫情防控数据
  • 郑州 网站报价百度搜索关键词热度
  • 常熟建设局网站首页百度官方推广
  • 温州专业网站建设网站查询
  • 个人网站号备案吗百度快照收录
  • 中山市西区网站制作seo基础知识考试
  • 网站建设 任务国内设计公司前十名