对于C++教材应用部分

栗子1:

这里写图片描述

//-----------------------------------test.h

#ifndef _TEST1_H_
#define _TEST1_H_

#include "iostream"
using namespace std;

class oval_shaped
{
public:
    oval_shaped();
    void trabzd();
    void outputl();
    void outputs();
    void mianji();
private:
    double axis_a,axis_b;       //长短半轴
    double h,xk_answer,answer,xk[101];
    double s;
protected:
    double fun(double x);
};
#endif

//-----------------------------------test.cpp
#include "test1.h"

oval_shaped::oval_shaped()
{
    cout<<"输入椭圆的长半轴长: a= ";
    cin>>axis_a;
    cout<<"短半轴长: b= "<<endl;
    cin>>axis_b;
    xk_answer=0;
    h=3.14159/100;
    answer=0;
    xk[0]=0;
    xk[100]=3.14159;
}

void oval_shaped::trabzd()      //划分坐标,数据相加
{
    int i;
    for(i=1;i<100;i++)
    {
        xk[i]=i*h;
        xk[i]=fun(xk[i]);
    }
    for(i=1;i<100;i++)
        xk_answer=xk_answer+xk[i];
    answer=0.5*(xk[0]+xk[100]+xk_answer)*h;
}

void oval_shaped::outputl()
{
    cout<<"该椭圆的周长为:"<<answer<<"."<<endl;
}

void oval_shaped::outputs()
{
    cout<<"该椭圆的面积为:"<<s<<"."<<endl;
}

double oval_shaped::fun(double x)
{
    return 2*sqrt(axis_a*axis_a*sin(x)*sin(x)+axis_b*axis_b*cos(x)*cos(x));
}

void oval_shaped::mianji()
{
    s=3.14159*axis_a*axis_b;
}
//-----------------------------------mine.cpp
#include "test1.h"
using namespace std;

char interface()
{
    char ch;
    cout<<"请选择"<<endl<<"1.计算椭圆的周长,请按【C】"<<endl\
                        <<"2.计算椭圆的面积,请按【S】"<<endl\
                        <<"3.退出,请按其他任意键 "<<endl;
    cin>>ch;
    return ch;
}

int main()
{
    for(;;)
    {
        oval_shaped os;
        char choose=interface();
        switch(choose)
        {
        case 'c':       //求周长时用定积分方法
            os.trabzd();
            os.outputl();
            break;
        case 's':       //求面积时用的是最简单的公式,当然前面的周长也可以用公式
            os.mianji();
            os.outputs();
            break;
        default:
            cout<<"输入选择错误,请重新输入!"<<endl;
            break;
        }
    }
}

栗子2:

//-----------------------------------MyHttp.h
#ifndef _MYHTTP_H_
#define _MYHTTP_H_

#include "iostream"
#include "cstring"
#include "cstdio"
#include "cstdlib"
#include "fcntl.h"
#include "io.h"
#include "winsock.h"

using namespace std;

class CMyHttp
{
public:
    void GetData();
    void CloseHttp();
    bool OpenHttp();

    CMyHttp();
    CMyHttp(LPCSTR lpServerName,LPCSTR lpFileName);
    virtual ~CMyHttp();
private:
    char server[200];           //存放服务器名
    char filename[200];         //存放服务器文件名
    IN_ADDR iaHost;
    LPHOSTENT lpHostEntry;
    SOCKET Socket;
    LPSERVENT lpServEnt;
    SOCKADDR_IN saServer;
    char szBuffer[1024];
};

#endif
//-----------------------------------MyHttp.cpp
#include "MyHttp.h"

CMyHttp::CMyHttp()
{
    strcpy(this->server,"localhost");
    strcpy(this->filename,"/");
}

CMyHttp::CMyHttp(LPCSTR lpServerName,LPCSTR lpFileName)
{
    strcpy(this->server,"lpServerName");
    strcpy(this->filename,"lpFileName");
    //重载构造函数使用this指针表示给当前建立的对象提供一特定的服务器名和服务器文件名
}

/*
1.strcpy(字符数组1,字符串2);//将字符串2复制到字符数组1中去(包括字符串结尾符'\0')
2.this:
this指针是某个类对象(通常指当前操作的对象)的起始地址,通过这个地址可以获得该对象的数据和成员函数
可以这样理解,this指针是隐含于每一个成员函数(包括构造函数和析构函数,但不包括静态成员函数)中特殊的指针,他用于指向正在被成员函数操作的对象。

*/
CMyHttp::~CMyHttp()
{}

bool CMyHttp::OpenHttp()            //建立与http的连接
{
    WORD wVersionRequested=MAKEWORD(1,1);           //使用1.1版本的套接字
    WSADATA wsaData;
    int nRet;
    nRet=WSAStartup(wVersionRequested,&wsaData);
    if(nRet)
    {
        cerr<<endl<<"WSAStartup()"<<nRet<<endl;
        WSACleanup();
        return false;
    }
    if(wsaData.wVersion!=wVersionRequested)         //检查WinSock的版本
    {
        cerr<<endl<<"WinSock version not supported"<<endl;
        WSACleanup();
        return false;
    }

    iaHost.s_addr=inet_addr(server);            //使用inet_addr()函数检查主机是名称还是ip地址
    if(iaHost.s_addr==INADDR_NONE)
    {
        //不是ip地址
        lpHostEntry=gethostbyname(server);
    }
    else
    {
        //是ip地址

        lpHostEntry=gethostbyaddr((const char *)&iaHost,sizeof(struct in_addr),AF_INET);
    }
    if(lpHostEntry==NULL)
    {
        cerr<<"gethostbyname()";
        return false;
    }

    Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(Socket==INVALID_SOCKET)
    {
        cerr<<"socket()";
        return false;
    }
    //寻找Http服务上的tcp端口号
    lpServEnt=getservbyname("http","tcp");
    if(lpServEnt==NULL)
        saServer.sin_port=htons(80);            //设置端口号为80;
    else
        saServer.sin_port=lpServEnt->s_port;
    //填充服务器地址结构的剩余部分
    saServer.sin_family=AF_INET;
    saServer.sin_addr=*((LPIN_ADDR)*lpHostEntry->h_addr_list);
    //连接socket
    nRet=connect(Socket,(LPSOCKADDR)&saServer,sizeof(SOCKADDR_IN));
    if(nRet==SOCKET_ERROR)
    {
        cerr<<"connect()";
        closesocket(Socket);
        return false;   
    }
    //格式化http请求
    sprintf(szBuffer,"GET %s\n",filename);
    nRet=send(Socket,szBuffer,strlen(szBuffer),0);
    if(nRet==SOCKET_ERROR)
    {
        cerr<<"send()";
        closesocket(Socket);
        return false;   
    }
    return true;
}

void CMyHttp::CloseHttp()
{
    //关闭socket
    closesocket(Socket);
    //释放winsock
    WSACleanup();
}

void CMyHttp::GetData()
{
    int nRet;
    //获取文件内容并输出到标准输出设备
    while(1)
    {
        //等待接接收
        nRet=recv(Socket,szBuffer,sizeof(szBuffer),0);
        if(nRet==SOCKET_ERROR)
        {
            cerr<<"recv()";
            break;
        }
        //判断服务器是否关闭了连接
        if(nRet==0)
        {
            break;  
        }
        //输出文件内容
        cout.write(szBuffer,nRet);
    }
}
//-----------------------------------gethttp.cpp
#include "MyHttp.h"
#include "iostream"

#pragma comment(lib,"ws2_32.lib")

int main(int argc,char **argv)
{
    int nRet;
    if(argc!=3)
    {
        cerr<<endl<<"用法:GetHTTP ServerName FullPathName"<<endl;
    //  return;
    }

    CMyHttp myHttp(argv[1],argv[2]);
    _setmode(_fileno(stdout),_O_BINARY);        //设置输出流方式为二进制模式
    if(myHttp.OpenHttp())
    {
        myHttp.GetData();
        myHttp.CloseHttp();
    }
    return 0;
}

解释:
1)

int WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData );
//WSA(Windows Sockets Asynchronous,Windows异步套接字)的启动命令.
//当一个应用程序调用WSAStartup函数时,操作系统根据请求的Socket版本来搜索相应的Socket库,
//然后绑定找到的Socket库到该应用程序中。以后应用程序就可以调用所请求的Socket库中的其它Socket函数了。

⑴ wVersionRequested:一个WORD(双字节)型数值,指明程序请求使用的Socket版本,其中高位字节指明副版本,低位字节指明主版本。
⑵lpWSAData 指向WSADATA数据结构的指针,用来接收Windows Sockets[1] 实现的细节,表明请求的Socket的版本信息。结构体如下:

//WSADATA结构被用来存储被WSAStartup函数调用后返回的Windows Sockets数据。
typedef struct WSAData {
        WORD                    wVersion;
        WORD                    wHighVersion;
#ifdef _WIN64
        unsigned short          iMaxSockets;
        unsigned short          iMaxUdpDg;
        char FAR *              lpVendorInfo;
        char                    szDescription[WSADESCRIPTION_LEN+1];
        char                    szSystemStatus[WSASYS_STATUS_LEN+1];
#else
        char                    szDescription[WSADESCRIPTION_LEN+1];
        char                    szSystemStatus[WSASYS_STATUS_LEN+1];
        unsigned short          iMaxSockets;
        unsigned short          iMaxUdpDg;
        char FAR *              lpVendorInfo;
#endif
} WSADATA;

typedef WSADATA FAR *LPWSADATA;

a. iMaxSockets
单个进程能够打开的socket的最大数目。Windows Sockets的实现能提供一个全局的socket池,可以为任何进程分配;或者它也可以为socket分配属于进程的资源。这个数字能够很好地反映Windows Sockets DLL或网络软件的配置方式。应用程序的编写者可以通过这个数字来粗略地指明Windows Sockets的实现方式对应用程序是否有用。例如,X Windows服务器在第一次启动的时候可能会检查iMaxSockets的值:如果这个值小于8,应用程序将显示一条错误信息,指示用户重新配置网络软件(这是一种可能要使用szSystemStatus文本的场合)。显然无法保证某个应用程序能够真正分配iMaxSockets个socket,因为可能有其它WindowsSockets应用程序正在使用。
b. iMaxUdpDg
Windows Sockets应用程序能够发送或接收的最大的用户数据包协议(UDP)的数据包大小,以字节为单位。如果实现方式没有限制,那么iMaxUdpDg为零。在Berkeley sockets的许多实现中,对于UDP数据包有个固有的限制(在必要时被分解),大小为8192字节。Windows Sockets的实现可以对碎片重组缓冲区的分配作出限制。对于适合的WindowsSockets 实现,iMaxUdpDg的最小值为512。注意不管iMaxUdpDg的值是什么,都不推荐你发回一个比网络的最大传送单元(MTU)还大的广播数据包。(Windows Sockets API 没有提供发现MTU的机制,但是它不会小于512个字节)。WinSock2.0版中已被废弃。

2)

int PASCAL FAR WSACleanup (void);

应用程序或DLL在使用Windows Sockets服务之前必须要进行一次成功的WSAStartup()调用.当它完成了Windows Sockets的使用后,应用程序或DLL必须调用WSACleanup()将其从Windows Sockets的实现中注销,并且该实现释放为应用程序或DLL分配的任何资源.

3)
先来看

typedef struct in_addr {
        union {
                struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;
                struct { USHORT s_w1,s_w2; } S_un_w;
                ULONG S_addr;
        } S_un;
#define s_addr  S_un.S_addr /* can be used for most tcp & ip code */
//IPv4地址占32位.注:联合体的内存由最大内存空间成员所占的空间决定
#define s_host  S_un.S_un_b.s_b2    // host on imp
#define s_net   S_un.S_un_b.s_b1    // network
#define s_imp   S_un.S_un_w.s_w2    // imp
#define s_impno S_un.S_un_b.s_b4    // imp #
#define s_lh    S_un.S_un_b.s_b3    // logical host
} IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;
in_addr_t inet_addr(const char *cp);
//是将一个点分十进制的IP转换成一个长整数型数(u_long类型)

参数:字符串,一个点分十进制的IP地址.(即是我们常见的ip:带点的十位字符串)
返回值:如果正确执行将返回一个无符号长整数型数。如果传入的字符串不是一个合法的IP地址,将返回INADDR_NONE。
详见http://roclinux.cn/?p=1160

插播

typedef struct hostent FAR *LPHOSTENT;

/*
 * Structures returned by network data base library, taken from the
 * BSD file netdb.h.  All addresses are supplied in host order, and
 * returned in network order (suitable for use in system calls).
 */

struct  hostent {
        char    FAR * h_name;           /* official name of host */
        char    FAR * FAR * h_aliases;  /* alias list */
        short   h_addrtype;             /* host address type */
        short   h_length;               /* length of address */
        char    FAR * FAR * h_addr_list; /* list of addresses */
#define h_addr  h_addr_list[0]          /* address, for backward compat */
};

4)
详见http://andylin02.iteye.com/blog/662965

struct hostent* gethostbyname(const char *name);
//返回对应于给定主机名的包含主机名字和地址信息的hostent结构指针。结构的声明与gethostbyaddr()中一致。
struct hostent * gethostbyaddr(const char * addr, socklen_t len, int family);
//返回一个指向hostent结构指针。

addr参数实际上不是char * 类型,而是一个指向存放IPv4地址的某个in_addr结构的指针;
len参数是这个结构的大小;
family参数为AF_INET.

5)

int socket( int af, int type, int protocol);
//创建一个能够进行网络通信的套接字
//若无错误发生,socket()返回引用新套接口的描述字。否则的话,返回INVALID_SOCKET错误.

af:一个地址描述。目前仅支持AF_INET格式,也就是说ARPA Internet地址格式。表示套接字要使用的协议簇,协议簇的在“linux/socket.h”里有详细定义,常用的协议簇:
AF_UNIX(本机通信)
AF_INET(TCP/IP – IPv4)
AF_INET6(TCP/IP – IPv6)
type:指定socket类型。新套接口的类型描述类型,如TCP(SOCK_STREAM)和UDP(SOCK_DGRAM)。常用的socket类型有,SOCK_STREAM(流套接字)、SOCK_DGRAM(数据报套接字)、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。
protocol:指定套接口所用的协议。如调用者不想指定,可用0。常用的协议有,IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。

再说明:

SOCK_STREAM 提供有序的、可靠的、双向的和基于连接的字节流,使用带外数据传送机制,为Internet地址族使用TCP。
SOCK_DGRAM 支持无连接的、不可靠的和使用固定大小(通常很小)缓冲区的数据报服务,为Internet地址族使用UDP。
SOCK_STREAM类型的套接口为全双向的字节流。对于流类套接口,在接收或发送数据前必需处于已连接状态。用connect()调用建立与另一套接口的连接,连接成功后,即可用send()和recv()传送数据。当会话结束后,调用closesocket()。带外数据根据规定用send()和recv()来接收。
实现SOCK_STREAM类型套接口的通讯协议保证数据不会丢失也不会重复。如果终端协议有缓冲区空间,且数据不能在一定时间成功发送,则认为连接中断,其后续的调用也将以WSAETIMEOUT错误返回。
SOCK_DGRAM类型套接口允许使用sendto()和recvfrom()从任意端口发送或接收数据报。如果这样一个套接口用connect()与一个指定端口连接,则可用send()和recv()与该端口进行数据报的发送与接收。

6)

struct servent FAR * PASCAL FAR getservbyname(const char
Far * name, const char FAR *proto);
//返回与给定服务名对应的包含名字和服务号信息的servent结构指针
//如果没有错误发生,getservbyname()返回如上所述的一个指向servent结构的指针,
//否则,返回一个空指针。

name: 一个指向服务名的指针。
proto: 指向协议名的指针。

再解释:

A.先看 LPSERVENT(指向该结构的指针)

typedef struct servent FAR *LPSERVENT;

struct  servent {
        char    FAR * s_name;           /* official service name */
        char    FAR * FAR * s_aliases;  /* alias list */
#ifdef _WIN64
        char    FAR * s_proto;          /* protocol to use */
        short   s_port;                 /* port # */
#else
        short   s_port;                 /* port # */
        char    FAR * s_proto;          /* protocol to use */
#endif
};

成员 用途
s_name 正规的服务名。
s_aliases 一个以空指针结尾的可选服务名队列。
s_port 连接该服务时需要用到的端口号,返回的端口号是以网络字节顺序排列的。
s_proto 连接该服务时用到的协议名。
返回的指针指向一个由Windows Sockets实现分配的结构。应用程序不应该试图修改这个结构或者释放它的任何部分。此外,每一线程仅有一份这个结构的拷贝,所以应用程序应该在发出其他Windows Scokets API调用前,把自己所需的信息拷贝下来.

下面插播htons()

/***
htons是将整型变量从主机字节顺序转变成网络字节顺序,
就是整数在地址空间存储方式变为:高位字节存放在内存的低地址处。
例1
假定你的数据是0x1234
在网络字节顺序里 这个数据放到内存中就应该显示成
addr addr+1
0x12 0x34
而在x86电脑上,数据0x1234放到内存中实际是:
addr addr+1
0x34 0x12
htons 的用处就是把实际主机内存中的整数存放方式调整成网络字节顺序。
例2
我们在Intel机器下,执行以下程序

voidmain()
{
inta=16,b;
b=htons(a);
cout<<"a="<<a<<endl;
cout<<"b="<<b<<endl;
}
结果a=16.b=4096.
数字16的16进制表示为0x0010,数字4096的16进制表示为0x1000。 
由于Intel机器是小尾端,存储数字16时实际顺序为1000,存储4096时实际顺序为0010。
因此在发送网络包时为了报文中数据为0010,需要经过htons进行字节转换。
***/

B.再看SOCKADDR_IN

typedef struct sockaddr_in SOCKADDR_IN;
/*
 * Socket address, internet style.
 */
struct sockaddr_in {
        short   sin_family;
        u_short sin_port;
        struct  in_addr sin_addr;
        char    sin_zero[8];
};

sin_family表示地址类型,对于基于TCP/IP传输协议的通信,该值只能是AF_INET;
sin_prot表示端口号,例如:21 或者 80 或者 27015,总之在0 ~ 65535之间;
sin_addr表示32位的IP地址,例如:192.168.1.5 或 202.96.134.133;
sin_zero表示填充字节,一般情况下该值为0;

7)

 int connect(int s, const struct sockaddr * name, int namelen);
 //建立与指定socket的连接

s:标识一个未连接socket
name:指向要连接套接字的sockaddr结构体的指针
namelen:sockaddr结构体的字节长度

8)

int PASCAL FAR send( SOCKET s, const char FAR* buf, int len, int flags);
//向一个已经连接的socket发送数据,如果无错误,返回值为所发送数据的总数,否则返回SOCKET_ERROR。

s:一个用于标识已连接套接口的描述字。
buf:包含待发送数据的缓冲区。
len:缓冲区中数据的长度。
flags:调用执行方式。常为0.

不论是客户还是服务器应用程序都用send()来向TCP连接的另一端发送数据。客户程序一般用send()向服务器发送请求,而服务器通常用send()产生应答。
http://blog.sina.com.cn/s/blog_732784f70100t0ti.html

9)

 int setmode(int handle, unsigned mode);
 //设置打开文件方式.若返回值为-1,则表示不成功.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值