Webbench源码学习(一)

Webbench源码学习

源码下载

官网 http://home.tiscali.cz/~cz210552/webbench.html

源码运行

解压后可以发现代码文件只有socket.c和webbench.c

新建xcode工程,添加代码文件编译

报错:socket.c重定义

解决:删除webbench文件中的 #include “socket.c” 因为xcode会自动寻找。同时记得在webbench.c文件中新包含stdio.h和stdlib.h,因为现在不会自动包含socket.c下的头文件。

源码解析

socket.c

函数 int Socket(const char *host, int clientPort) 将主机名转化为ip地址后建立连接

Socket网络编程常用的结构体及函数小结

Socket套接字,本意是插座,在网络中用来描述计算机中不同程序与其他计算机程序的通信方式。

常用的套接字类型有3种:(1)流套接字(SOCK——STREAM):使用了面向连接的可靠的数据通信方式,即TCP协议;(2)数据报套接字(Raw Sockets):使用了不面向连接的数据传输方式,即UDP;(3)原始套接字(SOCK——RAW):没有经过处理的IP数据包,可以根据自己程序的要求进行封装。

套接字相关的数据类型:sockaddr和sockaddr_in 用来保存一个套接字的信息。

区别:sockaddr_in将ip地址与端口分开为不同的成员。可以相互转换。

struct sockaddr
{
    unsigned short int sa_family; //指定通信地址类型,如果是TCP/IP通信,则值为AF_inet
    char sa_data[14]; //最多用14个字符长度,用来保存IP地址和端口信息
};

struct sockaddr_in
{
    unsigned short int sin_family; //指定通信地址类型
    uint16_t sin_port; //套接字使用的端口号
    struct in_addr sin_addr; //需要访问的IP地址
    unsigned char sin_zero[8]; //未使用的字段,填充为0
};

struct in_addr
{
    uint32_t  s_addt;
};

用来保存主机信息的结构体:hostent

struct hostent
{
    char *h_name;//正式的主机名称
    char **h_aliases;//这个主机的别名
    int  h_addrtype;//主机名的类型
    int  h_length;//地址的长度
    char **h_addr_list;//从域名服务器取得的主机地址
};

用来保存协议相关信息的结构体:protent

struct protoent
{
    char *p_name;//协议的名称
    char **p_aliases;//协议的别名
    int p_proto;//协议的序号
};

用来保存服务相关信息的结构体:servent

struct servent
{
    char *s_name;//这个服务的名称
    char **s_aliases;//这个服务可能的别名
    int s_port;//这个服务可能的端口
    char *s_proto;//这个服务可能使用的协议
};

*以上结构体都存在一一对应的get函数

常用函数

  • 创建套接字函数 int socket(int domain,int type,int protocol);

    参数domain用于指定创建套接字所使用的协议族(可取AF_UNIX,AF_INET,AF_INTE6),参数type指定套接字的类型(可取SOCK_STREAM,SOCK_DGRAM,SOCK_RAW),参数protocol通常设置为0。

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

    参数sockfd是一个由函数socket创建的套接字,参数serv_addr是一个地址结构,指定服务器的IP地址和端口号,参数addrlen为参数serv_addr的长度。

  • 套接字与端口绑定函数 int bind(int sockfd,struct sockaddr *my_addr,socklen_t addrlen);

    一般只有服务器端的程序调用,参数my_addr指定了sockfd将绑定到的本地地址,可以将参数my_addr的sin_addr设置为INADDR_ANY而不是某个确定IP地址就可以绑定到任何网络接口。

  • 接收连接请求函数 int accept(int s,struct sockaddr *addr,socklen_t *addrlen);

    参数s是由函数socket创建,经函数bind绑定到本地某一端口上,然后通过函数listen转化而来的监听套接字,参数addr用来保存发起连接请求的主机的地址和端口,参数addrlen是addr所指向的结构体的大小。

  • TCP套接字发送数据函数 ssize_t send(int s,const void *msg,size_t len,int flags);

    函数只能对处于连接状态的套接字使用,参数s为已建立好连接的套接字描述符,即accept函数的返回值,参数msg指向存放待发送数据的缓冲区,参数len为待发送数据的长度,参数flags为控制选项,一般设置为0。

  • TCP套接字接收数据函数 ssize_t recv(int s,void *buf,size_t len,int flags);

    函数recv从参数s所指定的套接字描述符(必须是面向连接的套接字)上接收数据并保存到参数buf所指定的缓冲区,参数len则为缓冲区长度,参数flags为控制选项,一般设置为0。

  • UCP套接字发送数据函数 ssize_t sendto(int s,const void *msg,size_t len,int flags,const struct sockaddr *to,socklen_t tolen);

    函数功能与函数send类似,但函数sendto不需要套接字处于连接状态,所以该函数通常用来发送UDP数据,同时因为是无连接的套接字,在使用sendto时需要指定数据的目的地址,参数msg指向待发送数据的缓冲区。参数len指定了待发送数据的长度,参数flags是控制选项,含义与send函数中的一致,参数to用于指定目的地址,目的地址的长度由tolen指定。

  • UDP套接字接收数据函数 ssize_t recvfrom(int s ,void *buf,size_t len,int flags,struct sockaddr *from,socklen_t *fromlen);

    与函数recv功能类似,只是函数recv只能用于面向连接的套接字,而函数recvfrom没有此限制,可以用于从无连接的套接字上接收数据。参数buf指向接收缓冲区,参数len指定了缓冲区的大小,参数flags是控制选项,含义与recv中的一致,如果参数from非空,且该套接字不是面向连接的,则函数recvfrom返回时,参数from中将保存数据的源地址,参数fromlen在调用recvfrom前为参数from的长度,调用recvfrom后将保存from的实际大小。

* 源码注释
int Socket(const char *host, int clientPort)
{
    int sock; //套接字
    unsigned long inaddr; //保存IP地址
    struct sockaddr_in ad; //新建socket结构体
    struct hostent *hp; //新建主机结构体

    memset(&ad, 0, sizeof(ad)); //初始化
    ad.sin_family = AF_INET; //通信地址类型ipv4

    inaddr = inet_addr(host); //点分十进制的IP转换成一个长整数型数(u_long类型)

    //host为ip地址时
    if (inaddr != INADDR_NONE) // #define INADDR_NONE 0xffffffff 无效IP地址
        memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr)); //保存到socket结构体
    //host为域名时
    else
    {
        hp = gethostbyname(host); //返回对应于给定主机名的包含主机名字和地址信息的hostent结构指针
        if (hp == NULL)
            return -1; //调用失败
        memcpy(&ad.sin_addr, hp->h_addr, hp->h_length); //保存到socket结构体
    }
    ad.sin_port = htons(clientPort); //设置端口号

    sock = socket(AF_INET, SOCK_STREAM, 0); //创建套接字 使用TCP协议
    if (sock < 0) //socket返回的值是一个文件描述符,0,1,2分别表示标准输入、标准输出、标准错误。所以其他打开的文件描述符都会大于2,错误时就返回 -1
        return sock;
    if (connect(sock, (struct sockaddr *)&ad, sizeof(ad)) < 0) //建立连接 0 成功 SOCKET_ERROR 错误(<0)可用WSAGETLASTERROR函数取错误码
        return -1;
    return sock; //返回socket
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值