研读tinyhttpd发现的函数

一.socket

#include<sys/socket.h>
int socket(int domain, int type, int protocal);
  • 函数作用:创建一个socket *

  • @param domain 告诉系统使用哪个底层协议族,IPv4还是IPv6

  • @param type 指定服务类型

  • @param protocal 一般默认为0

  • @return 函数执行成功返回一个socket文件描述符,失败返回-1

第1个参数domain指定协议族,取值为PF_INET,用于IPv4;取值为PF_INET6,用于IPv6,本教程取值PF_INET。

第2个参数type指定服务类型,取值SOCK_STREAM(流服务,适用TCP协议)或者SOCK_UGRAM(数据包服务,使用UDP协议)

在网络编程前,我们需要调用socket创建个套接字

二.bind

#include<sys/socket.h>
#include<sys/types.h>
int bind(int sockfd, const stuct sockaddr *my_addr, socklen_t addrlen);
  • socket命名

  • @param sockfd socket文件描述符,上节socket函数返回的值

  • @param my_addr socket地址

  • @param addrlen socket地址的长度

  • @return 函数执行成功返回0,失败返回-1

第1个参数sockfd是用socket()函数创建的文件描述符。

第2个参数my_addr是指向一个结构为sockaddr参数的指针,sockaddr中包含了地址、端口和IP地址的信息。在进行地址绑定的时候,需要弦将地址结构中的IP地址、端口、类型等结构struct sockaddr中的域进行设置之后才能进行绑定,这样进行绑定后才能将套接字文件描述符与地址等接合在一起。

第3个参数addrlen是my_addr结构的长度,可以设置成sizeof(struct sockaddr)。使用sizeof(struct sockaddr)来设置套接字的类型和其对已ing的结构。

bind()函数的返回值为0时表示绑定成功,-1表示绑定失败。

三.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);

getsockname函数用于获取与某个套接字关联的本地协议地址,获取一个套接口的名字。

getpeername函数用于获取与某个套接字关联的外地协议地址

四.listen

#include <sys/socket.h>
int listen(int sockfd, int backlog);
  • 监听socket

  • @param sockfd socket文件描述符

  • @param backlog 提示内核监听队列的最大长度

  • @return 函数执行成功返回0,失败返回-1

套接字函数中表示让一个套接字处于监听到来的连接请求的状态,仅由TCP服务器调用,listent函数创建一个监听队列以存放待处理的客户连接,将套接字sockfd指定为被监听的socket(类似指定电话机处于可接受的状态)。其中backlog一般取值为5。

第一个参数是服务端套接字

第二个参数是等待连接队列的最大长度

千千万万要注意:这个10并不是表示客户端最大的连接数为10, 实际上可以有很多很多的客户端(实践证明也是如此)。返回:若成功则为0,若出错则为-1

五.accept

#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • 接受连接

  • @param sockfd 上述listen函数指定的监听socket

  • @param addr 请求连接方(即客户端)地址

  • @param addrlen 客户端地址长度

  • @return 函数执行成功返回一个新的连接socket,失败返回-1

accept函数返回值:一个新的连接socket(因此也称为已连接套接字),该socket唯一标示了接受的新连接。后续双方可以利用已连接套接字进行通信。

六.connect

#include <sys/types.h>
#include <sys/socket.h>

int connect(int sockfd, const struct sockaddr *server_addr, socklen_t *addrlen);
  • 建立连接

  • @param sockfd socket函数返回一个socket

  • @param server_addr 服务端地址

  • @param addrlen 服务端地址地址长度

  • @return 函数执行成功返回0,失败返回-1

服务端已经做好被动接受连接的准备,那么客户端需要调用如下函数主动连接服务端。
客户端利用connect函数连接服务端,如果连接成功后,其第一个参数sockfd就唯一标示这个连接。

十.close

#include <unistd.h>
int close(int sockfd);

关闭连接本质是关闭创建的socket(正如电话要挂断一样),sockfd是待关闭的socket,调用socket函数关闭。

十一.sockaddr—in

#include<netinet/in.h>
#include <arpa/inet.h>

//创建sockaddr_in结构体变量
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充
serv_addr.sin_family = AF_INET; //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr(“127.0.0.1”); //具体的IP地址
serv_addr.sin_port = htons(1234); //端口号

struct sockaddr和struct sockaddr_in这两个结构体用来处理网络通信的地址。

sockaddr在头文件#include <sys/socket.h>中定义,sockaddr的缺陷是:sa_data把目标地址和端口信息混在一起了;

sockaddr_in在头文件#include<netinet/in.h>或#include <arpa/inet.h>中定义,该结构体解决了sockaddr的缺陷,把port和addr 分开储存在两个变量中

sin_port和sin_addr都必须是网络字节序(NBO),一般可视化的数字都是主机字节序(HBO)。

总结

二者长度一样,都是16个字节,即占用的内存大小是一致的,因此可以互相转化。二者是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr。

sockaddr常用于bind、connect、recvfrom、sendto等函数的参数,指明地址信息,是一种通用的套接字地址。

sockaddr_in 是internet环境下套接字的地址形式。所以在网络编程中我们会对sockaddr_in结构体进行操作,使用sockaddr_in来建立所需的信息,最后使用类型转化就可以了。

一般先把sockaddr_in变量赋值后,强制类型转换后传入用sockaddr做参数的函数:sockaddr_in用于socket定义和赋值;sockaddr用于函数参数。

注释中标明了属性的含义及其字节大小,这两个结构体一样大,都是16个字节,而且都有family属性,不同的是:

sockaddr用其余14个字节来表示sa_data,而sockaddr_in把14个字节拆分成sin_port, sin_addr和sin_zero分别表示端口、ip地址。sin_zero用来填充字节使sockaddr_in和sockaddr保持一样大小。

sockaddr和sockaddr_in包含的数据都是一样的,但他们在使用上有区别:程序员不应操作sockaddr,sockaddr是给操作系统用的.

程序员应使用sockaddr_in来表示地址,sockaddr_in区分了地址和端口,使用更方便。

一般的用法为:

程序员把类型、ip地址、端口填充sockaddr_in结构体,然后强制转换成sockaddr,作为参数传递给系统调用函数。

十二.pthread_create

#include<pthread.h>
int pthread_create(pthread_t*restrict tidp,const pthread_attr_t *restrict_attr,void**start_rtn)(void*),void *restrict arg);

第一个参数为指向线程标识符的指针。
第二个参数用来设置线程属性。
第三个参数是线程运行函数的起始地址。最后一个参数是运行函数的参数。
pthread_create是类Unix操作系统(Unix、Linux、Mac OS X等)的创建线程的函数。它的功能是创建线程(实际上就是确定调用该线程函数的入口点),在线程创建以后,就开始运行相关的线程函数。

C99 中新增加了 restrict 修饰的指针: 由 restrict 修饰的指针是最初唯一对指针所指向的对象进行存取的方法,仅当第二个指针基于第一个时,才能对对象进行存取。对对象的存取都限定于基于由 restrict 修饰的指针表达式中。

由 restrict 修饰的指针主要用于函数形参,或指向由 malloc() 分配的内存空间。restrict 数据类型不改变程序的语义。 编译器能通过作出 restrict 修饰的指针是存取对象的唯一方法的假设,更好地优化某些类型的例程。

另外,由于pthread库不是Linux系统默认的库,所以在使用pthread_create创建线程时,需要在编译中请加-lpthread参数。

十三.pthread_join

extern int pthread_join __P (pthread_t __th, void **__thread_return)

第一个参数为被等待的线程标识符
第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。

函数pthread_join用来等待一个线程的结束。

这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。

如果执行成功,将返回0,如果失败则返回一个错误号。

十四.newthread

谈谈new Thread的弊端及Java四种线程池的使用 - 孟凡柱的专栏 - 博客园 (cnblogs.com)

十五.PHP strcasecmp()

<?php
echo strcasecmp("shanghai","SHANGHAI");
?>
该函数返回:
0 - 如果两个字符串相等
<0 - 如果 string1 小于 string2
>0 - 如果 string1 大于 string2

比较两个字符串(不区分大小写):strcasecmp(string1,string2)

十六.PHP strncasecmp()

<?php
echo strncasecmp("I love China!","I love Shanghai!",6);
?>
本函数返回:
0 - 如果两个字符串相等
<0 - 如果 string1 小于 string2
>0 - 如果 string1 大于 string2

比较两个字符串(不区分大小写):strncasecmp(string1,string2,length)

十七.isspace

#include<ctype.h>
int isspace ( int c );  

isspace(), isblank() 函数判断一个字符是否是空白符 。
isblank() 所指的空白符是 isspace() 的一个子集。
返回值为非零(真)表示c是空白符,返回值为零(假)表示c不是空白符。

字符ASCII码 (十六进制)说明 (缩写)
’ ’0x20空格 (SPC)
‘\t’0x09水平制表符 (TAB)
‘\n’0x0a换行符 (LF)
‘\v’0x0b垂直制表符 (VT)
‘\f’0x0c换页 (FF)
‘\r’0x0d回车 (CR)

详见:limits.h头文件详解 (biancheng.net)

十八.<math.h>

__sin()和__sinpuf32()的区别: 原来per unit value指的是对2pi进行归一化的值。

然后在ccs中验证一下:

float j;
j=__sinpuf32(pi/6/2/PI)

仿真得到j=0.5,证明上面理解正确。但是如果直接写成 j = __sinpuf32(1/12);则结果为0

弧度与角度的关系为:弧度 = 180 / π 角度 角度 = π / 180 弧度。

使用 rtod( ) 函数可以将弧度值转换为角度值。 注意,使用 GCC 编译时请加入-lm

十九.select

  int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

注意,在系统调用 send() 和 recv() 中你应该使用新的套接字描述符 new_fd。如果你只想让一个连接进来,那么你可以使用 close() 去关闭原 来的文件描述符 sockfd 来避免同一个端口更多的连接。

当你第一次调用 socket() 建立套接口描述符的时候,内核就将他设置为阻塞。如果你不想套接口阻塞,你就要调用函数 fcntl():通过设置套接口为非阻塞,你能够有效地"询问"套接口以获得信息,但是一般来说轮询不是一个好主意,会浪费cpu时间,更好的方法是用 select()方法 去查询是否有数据要读进来select()–多路同步 I/Oselect() 让你可以同时监视多个套接口。如果你想知道的话,那么他就会告诉你哪个套接口准备读,哪个又准备好了写,哪个套接口又发生了例外 (exception)。

这个网站很不错(网络编程有关):http://cw.hubwiz.com/card/c/56f9ee765fd193d76fcc6c17/1/4/2/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值