网络编程复习

主机字节顺序转网络字节顺序

#include "stdafx.h"
#include "WinSock2.h"   //包含WinSock库头文件
#include "iostream"
#pragma comment(lib, "ws2_32.lib")  //链接WinSock导入库
using namespace std;
int main(int argc, char **argv)
{
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2,2); 
if(WSAStartup(wVersionRequested,&wsaData)!=0) 
{
     cout<<"加载WinSock DLL失败!\n";
     return 0;
}
u_short x, y=0x1234; //定义无符号短整型变量x、y,并将y初始化为十六进制数0x1234
x=htons(y);   //将y的值转换为网络字节顺序并将转换结果存入变量x 
//ntohs()网到主
cout<< "主机字节顺序:"<<hex<<y<< "\t网络字节顺序:"<<x<<endl;

u_long a, b=0x1122ABCD;  //定义无符号长整型变量a、b,并将b初始化
a= htonl(b);  //将b的值转换为网络字节顺序并将转换结果存入变量a
//ntohl()网到主
cout<< "主机字节顺序:"<<hex<<b<<"\t网络字节顺序:"<<a<<endl;
WSACleanup();  //注销WinSock DLL
return 0;
}


查询主机的名称、IP,输入域名并解析
#include "stdafx.h"
#include "WinSock2.h"   //包含WinSock库头文件
#include "iostream"
#pragma comment(lib, "ws2_32.lib")  //链接WinSock导入库
using namespace std;
int main(int argc, char **argv)
{
struct hostent *hptr;
char **pptr;
char hostname[256];  //用于存放获取的本机名称或输入的远程主机域名
/***初始化WinSock DLL***/ 
WSADATA wsaData;
WORD wVersionRequested =MAKEWORD(2,2);  //生成版本号2.2
if(WSAStartup(wVersionRequested,&wsaData)!=0)
{
     cout<<"加载WinSock DLL失败!\n";
     return 0;
}

if( gethostname(hostname,sizeof(hostname)) ) //获取本机名字
{
cout<<"获取主机名字失败!\n"<<endl;
WSACleanup();
return 0; 
}
cout<<"本机名字为:"<<hostname<<endl;
if( (hptr = gethostbyname(hostname)) == NULL) //获取本机IP地址
{
cout<<"通过主机名获取本机IP地址失败!\n"<<endl;
WSACleanup();
return 0; 
}
/***输出IP地址***/
pptr=hptr->h_addr_list;
cout<<"本机IP地址:"<<endl;
while(*pptr!=NULL)
{
cout<< inet_ntoa(*(struct in_addr *) (*pptr))<<endl; //长整型的Ip->点分十进制
pptr++;
}

/***从键盘输入要解析的网站的域名***/
cout <<"输入要解析的域名:"<<endl;
cin>>hostname;
if( (hptr = gethostbyname(hostname)) == NULL) //解析输入的网站域名
{
cout<<"名字解析失败!\n"<<endl;
WSACleanup();
return 0; 
}
/***输出远程机器IP地址***/
pptr=hptr->h_addr_list;
cout<<"主机IP地址:"<<endl;
while(*pptr!=NULL)
{
cout<< inet_ntoa(*(struct in_addr *) (*pptr))<<endl;  pptr++;
}
WSACleanup();
return 0;
}

显示使用TCP服务的名称与端口号
#include "stdafx.h"

#include "WinSock2.h" 
#include "iostream"
#pragma comment(lib, "ws2_32.lib")
using namespace std;
int main(int argc, char **argv)
{
/***初始化WinSock DLL***/ 
WSADATA wsaData;
WORD wVersionRequested =MAKEWORD(2,2);  //生成版本号2.2
if(WSAStartup(wVersionRequested,&wsaData)!=0)
{
     cout<<"加载WinSock DLL失败!\n";
     return 0;
}
struct servent * pServer;
for(int i=1;i<65535;i++)
{
// sptr = getservbyname("ftp", "tcp");//FTP using TCP
pServer=getservbyport(htons(i), "TCP");  //获取服务信息
if(pServer!=NULL)
{
cout<<"服务名:"<<pServer->s_name<<endl;
cout<<"协议:"<<pServer->s_proto<<endl;
cout<<"端口号:"<<ntohs(pServer->s_port)<<endl;
}
}
//注销WinSock DLL
WSACleanup();
return 0;
}
显示协议名称与协议号
#include "stdafx.h"

#include "WinSock2.h" 
#include "iostream"
#pragma comment(lib, "ws2_32.lib")
using namespace std;
int main(int argc, char **argv)
{
/***初始化WinSock DLL***/ 
WSADATA wsaData;
WORD wVersionRequested =MAKEWORD(2,2);  //生成版本号2.2
if(WSAStartup(wVersionRequested,&wsaData)!=0)
{
    cout<<"加载WinSock DLL失败!\n";
    return 0;
}
struct protoent *pProto;
for(int i=1;i<=256;i++)
{
if((pProto=getprotobynumber(i))!=NULL)
{
cout<<"协议名:"<< pProto->p_name<<endl;
cout<<"协议号:"<< pProto->p_proto <<endl;
}
}
WSACleanup();
return 0;
}

TCP 流式套接字 字符传输+文件传输
Client
#include "pch.h"
#include <iostream>
#include<WinSock2.h>
#include <fstream>
#define PORT 65432
#pragma warning(disable:4996)
#pragma comment(lib, "ws2_32.lib")
using namespace std;

struct Student
{
    char name[20];
    int Eng;

};
struct fileMessage {
    char fileName[256];
    long int fileSize;
};
void send_data(int sock_client)
{
    char name[20];
    int Eng;

    cin >> name;
    if (strcmp(name, "end") == 0)
    {
        struct Student stu;
        strcpy(stu.name, name);
        send(sock_client, (char *)&stu, sizeof(struct Student), 0);
        return;
    }
    cin >> Eng;
    struct Student stu;
    strcpy(stu.name, name);
    stu.Eng = Eng;

    stu.Eng = htonl(stu.Eng);

    send(sock_client, (char *)&stu, sizeof(struct Student), 0);
    cout << "信息发送完成!\n";
}
void send_file(int sock_client)
{
    char ok[3], filename[1000], file_buffer[1000];
    struct fileMessage fileMsg;
    cout << "输入要传输的文件路径:";

    cin>>filename;
    cout <<"D"<< filename << endl;
    
    int size = strlen(filename);

    while (filename[size] != '\\'&&size > 0)
    {
        size--;
    }
    strcpy(fileMsg.fileName, filename+size);

    ifstream inFile(filename, ios::in | ios::binary);

    if (!inFile.is_open())
    {
        cout << "Cannot open " << filename << endl;
        
        return ;  //文件打开失败则退出
    }

    inFile.seekg(0, ios::end);
    size = inFile.tellg();
    inFile.seekg(0, ios::beg);
    fileMsg.fileSize =htonl( size);
    send(sock_client, (char *)&fileMsg, sizeof(fileMsg), 0);

    if (recv(sock_client, ok, sizeof(ok), 0) <= 0)
    {
        cout << "接收OK失败,程序退出!\n";
        return ;
    }

    if (strcmp(ok, "ok") == 0)
    {
        while (!inFile.eof())
        {
            inFile.read(file_buffer, sizeof(file_buffer));
            size = inFile.gcount();
            send(sock_client, file_buffer, size, 0);

        }
        cout << "file transfer finished";//显示传输完成
        inFile.close();//关闭文件
    }
    else
        cout << "对方无法接收文件! ";

}

int main()
{
    int sock_client;
    struct sockaddr_in server_addr;
    int addr_len = sizeof(struct sockaddr_in);
    char msg[256];

    WSADATA wsaData;
    WORD wVersionRequested = MAKEWORD(2, 2);
    if (WSAStartup(wVersionRequested, &wsaData) != 0)
    {
        cout << "加载winsock.dll失败!\n";
        return 0;
    }

    if ((sock_client = socket(AF_INET, SOCK_STREAM,0)) <0)
    {
        cout << "创建套接字失败,错误代码:" << WSAGetLastError() << endl;
        WSACleanup();
        return 0;
    }

    char IP[100];
    cout << "请输入服务器IP地址:" << endl;
    cin >> IP;
    memset((void *)&server_addr, 0, addr_len);
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = inet_addr(IP);
    if (connect(sock_client, (struct sockaddr *)&server_addr, addr_len) != 0)
    {
        cout << "服务器连接失败,错误代码:" << WSAGetLastError() << endl;
        closesocket(sock_client);
        WSACleanup();
        return 0;
    }

    int size;
    if ((size = recv(sock_client, msg, sizeof(msg), 0)) < 0)
    {
        cout << "失败,错误代码:" << WSAGetLastError() << endl;
        closesocket(sock_client);
        WSACleanup();
        return 0;
    }
    else if (size == 0)
    {
        cout << "关闭连接,错误代码:" << WSAGetLastError() << endl;
        closesocket(sock_client);
        WSACleanup();
        return 0;
    }
    else
        cout << msg << endl;

    while (1)
    {
    //    send_data(sock_client);
        send_file(sock_client);
    }




    closesocket(sock_client);
    WSACleanup();
    return 0;
   
}

Server

#include "pch.h"
#include <iostream>
#include<fstream>
#include<direct.h>
#include <WinSock2.h>
#define PORT 65432
#pragma warning(disable:4996)
#pragma comment(lib, "ws2_32.lib")
using namespace std;


struct Student
{
    char name[20];
    int Eng;

};
struct fileMessage {
    char fileName[256];
    long int fileSize;
};

void recv_file(SOCKET sock_client)
{
    struct fileMessage fileMsg;
    long int filelen;
    char filename[1000] = "G:\\test\\";
    char ok[3] = "ok";
    char file_buffer[1000];
    _mkdir(filename);
    if ((recv(sock_client, (char *)&fileMsg, sizeof(fileMsg),0)) <= 0)
    {
        cout << "未接收到文件名字及文件长度!\n";
    
        return ;
    }
    filelen = ntohl(fileMsg.fileSize);
    strcat(filename, fileMsg.fileName);
    ofstream outFile(filename, ios::out | ios::binary);
    if(!outFile.is_open())
    {
        cout << "Cannot open " << filename << endl;
        return;
    }
    send(sock_client, ok, sizeof(ok),0);

    int size = 0;
    do
    {
        size = recv(sock_client, file_buffer, sizeof(file_buffer), 0);
        outFile.write(file_buffer, size);
        filelen -= size;
    } while (size != 0 && filelen > 0);

    cout << "Transfer finished!\n";
    outFile.close();

}
void recv_data(SOCKET new_sock)
{
    struct Student stu;
    if (recv(new_sock, (char *)&stu, sizeof(struct Student), 0) <= 0)
    {
        cout << "接收信息失败\n";
    }
    else
    {
        if (strcmp(stu.name, "end") == 0)
        {
            cout << "通信结束\n";
            return;
        }
        /*cout << client_addr.sin_port << " " << inet_ntoa(client_addr.sin_addr) << endl;
        struct sockaddr_in c_addr;
        int namelen;
        int n=getsockname(new_sock, (struct sockaddr *)&c_addr, &namelen);
        if (n == SOCKET_ERROR)
        {

        }
        else
        {
            cout << c_addr.sin_port << " " << inet_ntoa(c_addr.sin_addr) << endl;
        }*/
        stu.Eng = ntohl(stu.Eng);
        cout << stu.name << " " << stu.Eng << endl;
    }
}

int main()
{
    SOCKET sock_server;
    char msg[256];
    char msg1[] = "成功连接服务器";
    

    WSADATA wsaData;
    WORD wVersionRequests = MAKEWORD(2, 2);
    if (WSAStartup(wVersionRequests, &wsaData) != 0)
    {
        cout << "加载winsock.dll失败!\n";
        return 0;
    }

    if ((sock_server = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        cout << "创建套接字失败!错误代码:" << WSAGetLastError() << endl;
        WSACleanup();
        return 0;
    }

    int addr_len = sizeof(struct sockaddr_in);
    struct sockaddr_in addr;
    memset((void *)&addr, 0, sizeof(struct sockaddr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(sock_server, (struct sockaddr *)&addr, sizeof(addr)) != 0)
    {
        cout << "地址绑定失败!错误代码:" << WSAGetLastError() << endl;
        closesocket(sock_server);
        WSACleanup();
        return 0;

    }

    if (listen(sock_server, 0) != 0)
    {
        cout << "listen函数调用失败!错误代码:" << WSAGetLastError() << endl;
        closesocket(sock_server);
        WSACleanup();
        return 0;
    }
    else
        cout << "listenning......\n";

    int size;
    struct sockaddr_in client_addr;
    SOCKET new_sock;
    if ((new_sock = accept(sock_server, (struct sockaddr *)&client_addr, &addr_len))== INVALID_SOCKET)
    {
        cout << "accept函数调用失败!错误代码:" << WSAGetLastError() << endl;
        closesocket(sock_server);//关闭监听套接字
        WSACleanup();//注销WinSock动态链接库
        return 0;
    }
    else
    {
        int size = send(new_sock, msg1, sizeof(msg1), 0);
        if (size < 0)
        {
            cout << "发送信息失败!错误代码:" << WSAGetLastError() << endl;
            closesocket(new_sock);//关闭已连接套接字
            closesocket(sock_server);//关闭监听套接字
            WSACleanup();//注销WinSock动态链接库
            return 0;
            

        }
        else if (size == 0)
        {
            cout << "对方已关闭连接!\n";
            closesocket(new_sock);//关闭已连接套接字
            closesocket(sock_server);//关闭监听套接字
            WSACleanup();//注销WinSock动态链接库
            return 0;
            
        }
        else
        {
            cout << "信息发送成功!\n";
        }
        cout << "收到的信息为:\n";

        while (1)
        {
            //recv_data(new_sock);
            recv_file(new_sock);
        }
        

        closesocket(new_sock);
    }
    closesocket(sock_server);//关闭监听套接字
    WSACleanup();//注销WinSock动态链接库
    return 0;
}
TCP 流式套接字 多线程文件传输
Server(多连接客户发送)
#include "stdafx.h"
#include "iostream"
#include "fstream"
#include "process.h"  //使用C++运行库中的函数创建多线程
#include "winsock2.h"
#define PORT 65432    //定义服务器的监听端口号
#pragma comment(lib,"ws2_32.lib")
using namespace std;
char Command[20]="";//存放从键盘接收到的结束命令
char filename[128];  //存放从键盘输入的含有信息的文件名
char fname[128];  //存放发送给客户端的无路径信息的文件名
ifstream inFile;  //定义文件输入流
unsigned int _stdcall  GetCommand(void *par);  //声明输入close命令的线程函数
unsigned int _stdcall  SendFile(void *par); //声明发送文件的线程函数
int main()
{
    /***定义相关的变量***/
    int sock_server;  
    struct sockaddr_in addr,client_addr;
    unsigned hThread1, hThread2;
    unsigned int ThreadID1,ThreadID2;
    int addr_len = sizeof(struct sockaddr_in);
    cout<<"请输入要发送的文件名:\n";
    cin>>filename;
    /***以二进制读方式打开要分发的文件***/
    inFile.open(filename, ios::in|ios::binary);//打开文件
    if(!inFile.is_open()) 
    {
        cout<<"Cannot open "<<filename<<endl;
        return 0;  //文件打开失败则退出
    }
    /***截取发送给客户端的文件名***/
    int len=strlen(filename);
    int i=len;
    while(filename[i]!='\\' && i>=0)i--;
    if(i<0)    i=0; else  i++;
    int m=0;
    while(filename[m+i]!='\0')
    {
        fname[m]=filename[m+i];
        m++;
    }
    /***初始化winsock DLL***/
     WSADATA wsaData;
     WORD wVersionRequested=MAKEWORD(2,2);  //生成版本号
     if(WSAStartup(wVersionRequested,&wsaData)!=0)
     {
         cout<<"加载winsock.dll失败!\n";
         return 0;
     }
    /***创建套接字***/
    if ((sock_server = socket(AF_INET,SOCK_STREAM,0))<0) //建立一个socket
    {
        cout<<"创建套接字失败!\n";
        WSACleanup();
        return 0;
    }
    /***设置套接字为非阻塞模式***/
    unsigned long ul =1;    //设置套接字选项参数
    int    nRet = ioctlsocket(sock_server, FIONBIO, (unsigned long*)&ul);    
    if (nRet == SOCKET_ERROR)
    {
        cout<<"设置套接字选项失败!\n";
        closesocket(sock_server);
        WSACleanup();
        return 0;
    }
    /***绑定IP端口***/
    memset((void *)&addr,0,addr_len);
    addr.sin_family =AF_INET;
    addr.sin_port = htons(PORT);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);//使用本机的所有IP地址
    if(bind(sock_server,(LPSOCKADDR)&addr,sizeof(addr))!=0)    
    {
        cout<<"绑定地址失败!\n";
        closesocket(sock_server);
        WSACleanup();
        return 0;
    }
    /***开始监听***/
    if(listen(sock_server,5)!=0)      
    {
        cout<<"listen函数调用失败!\n";
        closesocket(sock_server);
        WSACleanup();
        return 0;
    }
    else
        cout<<"listenning......\n"; 
    /***启动命令接收线程***/
    hThread1=_beginthreadex(NULL,0,GetCommand,(LPVOID)Command,0,&ThreadID1);
         /***接收并处理客户连接 ***/
    SOCKET newsock;
    while(1)
    {
        Sleep(10);
        if(strcmp(Command,"close")==0)break ;  //如果输入close命令则退出
        newsock = accept(sock_server,(LPSOCKADDR)&client_addr,&addr_len);
         if(newsock!=INVALID_SOCKET)
        {
            cout<<"cnnect from "<<inet_ntoa(client_addr.sin_addr)<<endl;
            hThread2=_beginthreadex(NULL,0,SendFile,(LPVOID)newsock,0,&ThreadID2);//启动文件发送线程
         }
    }
    inFile.close();
    closesocket(sock_server);
    return 0;
}
/*****************文件传输线程函数********************************/
unsigned int _stdcall  SendFile(void *par)
{
    
    char buffer[1000];
    inFile.seekg(0,ios::beg);//将文件读指针移动到文件头,如果少了本行,第二个客户收到的文件将是0字节

    SOCKET sock=(SOCKET)par;
    /***设置套接字为阻塞模式***/
    unsigned long ul =0;    //设置套接字选项
    int nRet = ioctlsocket(sock, FIONBIO, (unsigned long*)&ul);    
    
    send(sock,(char*)fname,strlen(fname)+1,0); //发送文件名
    int size=recv(sock,buffer,sizeof(buffer),0); //接收对方发来的“OK”消息
    cout<<buffer<<endl;
    if(strcmp(buffer,"OK")!=0)
    {
         cout<<"客户端出错!\n";
         closesocket(sock);  //关闭socket
         return 0;
     }

    /****传输文件内容****/
    while(!inFile.eof())
    {
        inFile.read(buffer,sizeof(buffer));
        size=inFile.gcount();  //获取实际读取的字节数
        send(sock,(char*)buffer,size,0);
    }
    cout<<"文件传输结束!\n";
    closesocket(sock);    //关闭socket
    return 0;
}
/*************从键盘接收命令的线程函数********************/
unsigned int _stdcall  GetCommand(void *par)
{
    char * p=(char *)par;
    while(strcmp(p,"close")!=0)
    {Sleep(10);gets(p);}
    return 0;
}
TCP 流式套接字 I/O模型
Client

Server

#include "stdafx.h"

#include "iostream"
#include "winsock2.h"
#define PORT 65432         //定义端口号常量
#define BUFFER_LEN 500   //定义接收缓冲区长度
#pragma comment(lib, "ws2_32.lib")
using namespace std;
int main(int argc, char **argv)
{
/***定义相关的变量***/
SOCKET sock_server,newsock; //定义监听套接字和临时已连接套接字变量
fd_set fdsock;  //保存所有套接字的集合
fd_set fdread;  //select要检测的可读套接字集合
struct sockaddr_in addr;//存放本地地址的sockaddr_in结构变量
struct sockaddr_in  client_addr;//存放客户端地址的sockaddr_in结构变量
char msgbuffer[BUFFER_LEN];//定义用于接收客户端发来信息的缓区
char msg[] ="Connect succeed. Please send a message to me.\n"; //发给客户端的信息
/***初始化winsock2.DLL***/
WSADATA wsaData;
WORD  wVersionRequested=MAKEWORD(2,2);  //生成版本号2.2
if(WSAStartup(wVersionRequested,&wsaData)!=0)
{
     cout<<"加载winsock.dll失败!\n";
     return 0;
}
/***创建套接字***/
if ((sock_server = socket(AF_INET,SOCK_STREAM,0))<0) 
{
    cout<<"创建套接字失败!\n";
    WSACleanup();
    return 0;
}
/***填写要绑定的本地地址***/
int addr_len = sizeof(struct sockaddr_in);
memset((void *)&addr,0,addr_len);
addr.sin_family =AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY);//允许套接字使用本机的任何IP
/***给监听套接字绑定地址***/
if(bind(sock_server,( struct sockaddr *)&addr,sizeof(addr))!=0)    
{
    cout<<"地址绑定失败!\n";
    closesocket(sock_server);
    WSACleanup();
    return 0;
}
/***将套接字设为监听状态****/
if(listen(sock_server,0)!=0)      
{
    cout<<"listen函数调用失败!\n";
    closesocket(sock_server);
    WSACleanup();
    return 0;
}
else
    cout<<"listenning......\n"; 
FD_ZERO(&fdsock);//初始化fdsock
FD_SET(sock_server, &fdsock);//将监听套接字加入到套接字集合fdsock
/***循环:接收连接请求并收发数据***/
while(true)
{
    FD_ZERO(&fdread);//初始化fdread
    fdread=fdsock;//将fdsock中的所有套接字添加到fdread中
    if(select(0, &fdread, NULL, NULL, NULL)>0)
    {
        for(int i=0;i<fdsock.fd_count;i++)
        {
            if (FD_ISSET(fdsock.fd_array[i], &fdread)) 
            {
                if(fdsock.fd_array[i]==sock_server)
                {    //有客户连接请求到达,接收连接请求
                    newsock=accept (sock_server, (struct sockaddr *) &client_addr, &addr_len);
                    if(newsock==INVALID_SOCKET) 
                    {  //accept出错终止所有通信,结束程序
                        cout<<"accept函数调用失败!\n";
                        for(int j=0;j<fdsock.fd_count;j++)
                        closesocket(fdsock.fd_array[j]); //关闭所有套接字
                        WSACleanup();//注销WinSock动态链接库
                        return 0; 
                    }
                    else
                    {
                        cout<<inet_ntoa(client_addr.sin_addr)<<"连接成功!\n";
                        send(newsock,msg,sizeof(msg),0) ;//发送一段信息
                        FD_SET(newsock, &fdsock);//将新套接字加入fdsock
                    }
                }
                else
                {    //有客户发来数据,接收数据
                    memset((void *) msgbuffer,0, sizeof(msgbuffer));//缓冲区清零
                    int size=recv(fdsock.fd_array[i],msgbuffer,sizeof(msgbuffer),0);
                    if(size<0) //接收信息
                        cout<<"接收信息失败!"<<endl;
                    else if(size==0)
                        cout<<"对方已关闭!\n";
                    else
                    {  //显示收到信息
                        getpeername(fdsock.fd_array[i], (struct sockaddr *)&client_addr, &addr_len); //获取对方IP地址
                         cout<< inet_ntoa(client_addr.sin_addr) <<":"<< msgbuffer << endl;
                    }
                    closesocket(fdsock.fd_array[i]);   //关闭套接字
                    FD_CLR(fdsock.fd_array[i],&fdsock);//清除已关闭套接字
                }
            }
        }
    }
    else
    {
        cout<<"Select调用失败!\n";
        break;//终止循环退出程序
    }
}
/***结束处理***/
for(int j=0;j<fdsock.fd_count; j++)
closesocket (fdsock.fd_array[j]);//关闭所有已连接套接字
WSACleanup();//注销WinSock动态链接库
return 0;
}
UDP 数据报套接字 p2p和广播
多线程
#include "stdafx.h"
#include "iostream"
#include "winsock2.h"
#define LOCALPORT 65431  //本端所用UDP端口号
#define PEERPORT  65432  //通信对端所用UDP端口号
#define PEERIP "127.0.0.1"  //通信对端IP地址,调试程序时可使用环回地址
#define BUFFER_LEN 1000
#pragma comment(lib,"ws2_32.lib")
using namespace std;
struct sockaddr_in  peeraddr,localaddr;//保存通信对端地址和本地地址的变量
int len =sizeof(struct sockaddr_in);//套接字函数中常用的地址长度
WSAEVENT bExit;//用于通知线程退出的事件对象句柄
/****************接收并显示信息的线程函数*****************/
DWORD WINAPI RecvMessage(LPVOID parsock)
{
    SOCKET recvsock=(SOCKET)parsock;
    char recvBuffer[BUFFER_LEN];
    int err;
    while(TRUE)
    {
    if(recvfrom(recvsock,recvBuffer,sizeof(recvBuffer),0,NULL,NULL)!=SOCKET_ERROR)
       //由于通信对端的地址已知,所以接收数据时可不必记录对方地址
        { 
            cout<< inet_ntoa(peeraddr.sin_addr)<<":"<<recvBuffer<<endl;
            if (strcmp(recvBuffer,"bye")==0) 
            {    //收到对方退出消息则结束本线程同时通知主线程
SetEvent(bExit); break;
} 
        }
        else
        {
            err=WSAGetLastError();
            if(err==WSAECONNRESET){cout<<"The peer is closed!\n";continue;}
            cout<<"recive error:"<<err<<endl;
            SetEvent(bExit);break;
        }
    }
    return 0;
}
/****************输入并发送信息的线程函数*****************/
DWORD WINAPI SendMessage(LPVOID parsock)
{
    SOCKET sendsock=(SOCKET)parsock; 
    char sendBuffer[BUFFER_LEN];
    while(true)
    {
        cout<<"Input the Message you want to send:"<<endl;
        cin.getline(sendBuffer,sizeof(sendBuffer));
        sendto(sendsock,sendBuffer,strlen(sendBuffer)+1,0,
(struct sockaddr*)& peeraddr,len);
        if (strcmp(sendBuffer,"bye")==0) 
        {//如果输入的是bye,则本线程结束,同时通知主线程
            SetEvent(bExit);
            break;
        }
    }
    return 0;
}
/****************程序主函数*****************/
int main(int argc, char* argv[])
{
    /***初始化winsock DLL***/
    WSADATA wsaData;
    WORD wVersionRequested=MAKEWORD(2,2);  //生成版本号2.2
    if(WSAStartup(wVersionRequested,&wsaData)!=0)
    {
        cout<<"没有找到合适的winsock.dll!\n";
        return 0;
    }
    /***创建事件对象***/
    bExit=WSACreateEvent();
    /***创建数据报套接字***/
    SOCKET udpsocket;
    udpsocket=socket(AF_INET,SOCK_DGRAM,0);    
    /***绑定本地地址***/
    localaddr.sin_family=AF_INET;    
    localaddr.sin_port=htons(LOCALPORT); //本端使用的UDP端口号    
    localaddr.sin_addr.s_addr= INADDR_ANY; //绑定本机所有IP地址
    bind(udpsocket,(struct sockaddr*)&localaddr,len);
    /***指定通信对端地址***/
    peeraddr.sin_family=AF_INET;    
    peeraddr.sin_port=htons(PEERPORT); //指定对端使用的IP端口号    
    peeraddr.sin_addr.s_addr= inet_addr(PEERIP) ;//指定对端的IP地址
    /***启动数据收发线程***/
    HANDLE hThrdsnd,hThrdrcv;
    DWORD nThrdsnd,nThrdrcv;
    hThrdsnd=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)SendMessage,
(LPVOID)udpsocket,0,&nThrdsnd);
    hThrdrcv=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RecvMessage,
(LPVOID)udpsocket,0,&nThrdrcv);
    /***等待线程的退出通知***/
    WaitForSingleObject(bExit, INFINITE);
    /***结束处理***/
    closesocket(udpsocket);
    WSACleanup();
    return 0;
}
WSAAsyncSelect
初始代码
if ((m_DGramSocket1 = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        CString str1("创建套接字失败");
        MessageBox(str1);
        CDialogEx::OnOK();
    }
    if ((m_DGramSocket2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        CString str1("创建套接字失败");
        MessageBox(str1);
        CDialogEx::OnOK();
    }
    memset((void *)&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(m_DGramSocket1, (LPSOCKADDR)&addr, sizeof(addr)) != 0)
    {
        MessageBox("绑定失败!");
        closesocket(m_DGramSocket1);
        CDialogEx::OnOK();
    }
    memset((void *)&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT1);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(m_DGramSocket2, (LPSOCKADDR)&addr, sizeof(addr)) != 0)
    {
        MessageBox("绑定失败!");
        closesocket(m_DGramSocket2);
        CDialogEx::OnOK();
    }


    if (WSAAsyncSelect(m_DGramSocket1, m_hWnd, MsgRecv, FD_READ) != 0)
    {
        MessageBox("套接字异步事件注册失败!");
        closesocket(m_DGramSocket1);
    }
    BOOL yes = TRUE;
    int vsize = sizeof(BOOL);
    setsockopt(m_DGramSocket2, SOL_SOCKET, SO_BROADCAST, (char *)&yes, vsize);
    if (WSAAsyncSelect(m_DGramSocket2, m_hWnd, MsgRecv, FD_READ) != 0)
    {
        MessageBox("套接字异步事件注册失败!");
        closesocket(m_DGramSocket2);
    }
消息接受函数
char recvBuffer[1000];
    CString str;
    int len = sizeof(fromaddr);
    int size = recvfrom(m_DGramSocket1, recvBuffer, sizeof(recvBuffer), 0, (sockaddr *)&fromaddr, &len);

    if (size > 0)
    {
        recvBuffer[size] = '\0';
        str.Format("来自于%s:%d的消息:%s", inet_ntoa(fromaddr.sin_addr), ntohs(fromaddr.sin_port), recvBuffer);
        m_ListBox.AddString(str);
    }
单个发送
UpdateData(true);  
    struct sockaddr_in toaddr;  
    DWORD bwaddr;  
    unsigned short mport;
    m_Ip.GetAddress(bwaddr);  
    mport = atoi(m_Port.GetString());
    memset((void *)&toaddr, 0, sizeof(addr));  
    toaddr.sin_family = AF_INET;  
    toaddr.sin_addr.s_addr = htonl(bwaddr);
    toaddr.sin_port = htons(mport);
    m_ListBox.AddString("我说:" + m_Edit);
    sendto(m_DGramSocket1, m_Edit, m_Edit.GetLength(), 0, (sockaddr*)&toaddr, sizeof(toaddr));  
广播
// TODO: 在此添加控件通知处理程序代码
    UpdateData(true);
    struct sockaddr_in toaddr;
    toaddr.sin_family = AF_INET;
    int mport = atoi(m_Port.GetString());
    toaddr.sin_port = htons(mport);
    toaddr.sin_addr.S_un.S_addr = INADDR_BROADCAST;
    int a = sendto(m_DGramSocket2, m_Edit, m_Edit.GetLength(), 0, (sockaddr *)&toaddr, sizeof(toaddr));
    m_ListBox.AddString("我说:" + m_Edit);


原始套接字
Ping
#include "stdafx.h"

#include <iostream>
#include <winsock2.h>
#pragma comment(lib, "WS2_32")
#define DATALEN 1012
#define  PACKAGENUM 10  //发送ICMP会从请求报文的个数
using namespace std;
/***定义ICMP包结构***/
typedef struct icmp_hdr
{
    unsigned char   icmp_type;        // ICMP包类型
    unsigned char   icmp_code;        // 代码
    unsigned short  icmp_checksum;    // 校验和
    unsigned short  icmp_id;        // 惟一确定此请求的标识,通常设置为进程ID
    unsigned short  icmp_sequence;    // 序列号
    unsigned long   icmp_timestamp; // 时间戳
} IcmpHeader;
unsigned short checksum(unsigned short* buff, int size);  //校验和计算函数的声明
int main(int argc, char *argv[ ])
{
    /***加载Winsock2.2***/
    WSADATA wsaData;
    int ret;
    if((ret=WSAStartup(MAKEWORD(1,0),&wsaData))!=0)
    {
        cout<<"初始化WinSock2.2出错!";
        exit(0);
    }
    char szDestIp[256] ={0};//存放要Ping的IP地址或域名
    //检查ping命令的使用格式是否正确,程序调试时可用后面的代码替换
    /*if (argc < 2)
     {
     cout<<"\n用法: ping IP地址|域名\n";
      return -1;
     }
    strcpy(szDestIp,argv[1]);*/
    /***输入对方IP地址,调试程序时使用***/
    cout<<"请输入你要Ping的IP地址...\n";
    cin.getline(szDestIp,sizeof(szDestIp));
    /***将点分十进制IP地址转换为32位二进制表示的IP地址***/
    unsigned long ulDestIP= inet_addr(szDestIp);   
    /****转换不成功时按域名解析****/
    if(ulDestIP == INADDR_NONE)
    {
        hostent* pHostent = gethostbyname(szDestIp);
        if (pHostent!=NULL)
            ulDestIP = (*(in_addr*)pHostent->h_addr).s_addr;
        else //解析主机名失败
        {
            cout<<"域名解析失败:"<<argv[1]<<"错误码:"<<WSAGetLastError()<<endl;
            WSACleanup();
            return -1;
        }
    }
    /**** 创建收发ICMP包的原始套接字***/
    SOCKET sRaw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    /***设置接收超时时间***/
    int nTime=1000;
    ret = setsockopt(sRaw, SOL_SOCKET,SO_RCVTIMEO, (char*)&nTime, sizeof(nTime));
    if(ret == SOCKET_ERROR)
    {
    cout<<"套接字选项设置出错!错误码:"<<WSAGetLastError()<<endl;
        return -1;;
    }
    /***设置ICMP包发送的目的地址***/
    SOCKADDR_IN dest;
    dest.sin_family = AF_INET;
    dest.sin_port = htons(0);
    dest.sin_addr.S_un.S_addr = ulDestIP;
    /***创建ICMP包***/
    char buff[sizeof(IcmpHeader) + DATALEN];
    IcmpHeader* pIcmp = (IcmpHeader*)buff;
    /***填写ICMP包数据***/
    pIcmp->icmp_type = 8;    // ICMP回送请求
    pIcmp->icmp_code = 0;
    pIcmp->icmp_id = (unsigned short)GetCurrentProcessId();//获取进程号作为ID 
    pIcmp->icmp_timestamp = 0; //时间戳暂设置为0,具体值发送时再填
    pIcmp->icmp_checksum = 0;  //校验和在计算前应先设置为0
    pIcmp->icmp_sequence = 0;  //初始序列号
    /***填充数据部分,可以为任意***/
    memset(&buff[sizeof(IcmpHeader)], 'A', DATALEN);
    /***调用connect()函数为原始套接字指定通信对端地址***/
    connect(sRaw,(SOCKADDR *)&dest, sizeof(dest));
    /***收发ICMP报文***/
    int n=0;
    bool bTimeout;  
    unsigned short    nSeq = 0;//发送的ICMP报文的序号
    char recvBuf[32+DATALEN];//定义接收缓冲区
    SOCKADDR_IN from;  //保存收到的数据的源地址
    int nLen = sizeof(from);  //地址长度
    IcmpHeader* pRecvIcmp;  //指向ICMP报文首部的指针
    while(TRUE)
    {
        static int nCount = 0;
        int nRet;
        if(nCount++ == PACKAGENUM)
            break;
        /***填写发送前才能填写的一些字段并发送ICMP包***/
        pIcmp->icmp_checksum = 0; 
        pIcmp->icmp_timestamp = GetTickCount();//时间戳
        pIcmp->icmp_sequence = nSeq++;  //包序号
        pIcmp->icmp_checksum=checksum((unsigned short*)buff, sizeof(IcmpHeader)+DATALEN);
        nRet = send(sRaw, buff, sizeof(IcmpHeader) + DATALEN, 0);
        if(nRet == SOCKET_ERROR)
        {
            cout<<"发送失败!错误码:"<<WSAGetLastError()<<endl;
            closesocket(sRaw);
            WSACleanup();
            return -1;
        }
        //接收对方返回的ICMP应答
        bTimeout=FALSE;
        n=0;
do{
            n++;//接收预期ICMP应答报文的尝试次数加1
            memset((void *)recvBuf,0,sizeof(recvBuf));
            nRet = recvfrom(sRaw, recvBuf, sizeof(recvBuf), 0, (sockaddr*)&from, &nLen);
            if(nRet == SOCKET_ERROR)
            {
                if(WSAGetLastError() == WSAETIMEDOUT)
                {
                    cout<<" timed out!\n";
                    bTimeout=TRUE;   //接收时间超时
                    break;
                }
                cout<<"接收失败!错误码:"<<WSAGetLastError()<<endl;
                return -1;
            }
             pRecvIcmp = (IcmpHeader*)(recvBuf + 20);
//收到的数据包含20个字节的IP首部,加20才是ICMP首部位置 
            if(pRecvIcmp->icmp_id != GetCurrentProcessId())
//收到报文是否为本程序发送的请求报文的应答报文
            {
                //不是则重新接收    
                cout<<" 收到一个非预期的ICMP报文,忽略!\n";
            }
            else  //是则退出循环
                break;
        }while(n<10);//重新接收次数不超过10则继续重试
        if(n>10)// 收到太多非预期的ICMP报文则退出
        {
            cout<<"对方机器向本机发送了太多的ICMP报文.\n";
            closesocket(sRaw);
            WSACleanup();
            return -1;
        }
        if(bTimeout)continue;  //接收超时则发送下一个ICPM报文
        /****解析接收到的ICMP包****/
        int nTick = GetTickCount();
        if(nRet < 20+ sizeof(IcmpHeader))  //收到的报文长度不足则不予解析
        {
            cout<<"Too few bytes from"<<inet_ntoa(from.sin_addr)<<endl;
            continue;
        }
        else
        {  
            //解析收到报文
            cout<<nRet<<" bytes from :"<<inet_ntoa(from.sin_addr);
            cout <<" icmp_seq = "<<pRecvIcmp->icmp_sequence;
            cout<<" time:"<< nTick - pRecvIcmp->icmp_timestamp<<" ms \n";
            Sleep(1000);  //延时1秒再发送下一个数据包
        }
    }
    closesocket(sRaw);
    WSACleanup();
    return 0;
}
/*************计算校验和的函数***************/
unsigned short checksum(unsigned short* buff, int size)
{
    unsigned long cksum = 0;
    while(size>1)
    {
        cksum += *buff++;
        size -= sizeof(unsigned short);
    }
    if(size)// 是奇数
        cksum += *(char*)buff;
    //将32位的chsum高16位和低16位相加然后取反
    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >> 16);            
    return (unsigned short)(~cksum);
}

猜你喜欢

转载自www.cnblogs.com/pxlsdz/p/12074088.html