• C++ 一个网络编程实例


    这只是一个小小的实例,包括Socket编程、多线程、文件操作。

    服务器代码:

       

    // Server.cpp : 定义控制台应用程序的入口点。

    #include "stdafx.h"
    #include <windows.h>
    #include <process.h>
    #include <iostream>
    #include "FileLog.h"
    #include "time.h"
    usingnamespace std;
    #pragma comment(lib,"ws2_32.lib")

    //多线程调用的方法只有一个指针型的参数,有时候需要多个参数,所以定义一个结构,参数作为结构的字段
    typedef struct _receiveStruct
    {
    SOCKET *Socket;
    FileLog *fileLog;
    _receiveStruct(SOCKET *_socket,FileLog *_fileLog):Socket(_socket),fileLog(_fileLog){}
    } ReceiveStruct;

    //获取今天日期的字符串
    string GetDate(constchar*format)
    {
    time_t tm;
    struct tm *now;
    char timebuf[20];
    time(&tm);
    now=localtime(&tm);
    strftime(timebuf,sizeof(timebuf)/sizeof(char),format,now);
    returnstring(timebuf);
    }

    //接收数据线程
    void receive(PVOID param)
    {
    ReceiveStruct* receiveStruct=(ReceiveStruct*)param;
    char buf[2048];
    int bytes;
    while(1)
    {
    //接收数据
    if((bytes=recv(*receiveStruct->Socket,buf,sizeof(buf),0))==SOCKET_ERROR){
    cout<<"接收数据失败!\n";
    _endthread();//终止当前线程
    }
    buf[bytes]='\0';
    cout<<"客户端说:"<<buf<<endl;
    receiveStruct->fileLog->Write("客户端 ").WriteLine(GetDate("%Y-%m-%d %H:%M:%S").c_str()).WriteLine(buf);//记录聊天内容
    }
    }

    //获取本机IP
    in_addr getHostName(void)
    {
    char host_name[255];
    //获取本地主机名称
    if (gethostname(host_name, sizeof(host_name)) == SOCKET_ERROR) {
    cout<<"Error %d when getting local host name."<<WSAGetLastError();
    Sleep(3000);
    exit(-1);
    }

    //从主机名数据库中得到对应的“IP”
    struct hostent *phe = gethostbyname(host_name);
    if (phe ==0) {
    cout<<"Yow! Bad host lookup.";
    Sleep(3000);
    exit(-1);
    }

    struct in_addr addr;
    memcpy(&addr, phe->h_addr_list[0], sizeof(struct in_addr));
    return addr;
    }

    //启动服务器
    SOCKET StartServer(void)
    {
    //创建套接字
    SOCKET serverSocket;
    if((serverSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET){
    cout<<"创建套接字失败!";
    Sleep(3000);
    exit(-1);
    }
    short port=1986;
    struct sockaddr_in serverAddress;
    //初始化指定的内存区域
    memset(&serverAddress,0,sizeof(sockaddr_in));
    serverAddress.sin_family=AF_INET;
    serverAddress.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    serverAddress.sin_port = htons(port);

    //绑定
    if(bind(serverSocket,(sockaddr*)&serverAddress,sizeof(serverAddress))==SOCKET_ERROR){
    cout<<"套接字绑定到端口失败!端口:"<<port;
    Sleep(3000);
    exit(-1);
    }

    //进入侦听状态
    if(listen(serverSocket,SOMAXCONN)==SOCKET_ERROR){
    cout<<"侦听失败!";
    Sleep(3000);
    exit(-1);
    }

    //获取服务器IP
    struct in_addr addr = getHostName();
    cout<<"Server "<<inet_ntoa(addr)<<" : "<<port<<" is listening......"<<endl;
    return serverSocket;
    }

    //接收客户端连接
    SOCKET ReceiveConnect(SOCKET &serverSocket)
    {
    SOCKET clientSocket;//用来和客户端通信的套接字
    struct sockaddr_in clientAddress;//用来和客户端通信的套接字地址
    memset(&clientAddress,0,sizeof(clientAddress));//初始化存放客户端信息的内存
    int addrlen =sizeof(clientAddress);

    //接受连接
    if((clientSocket=accept(serverSocket,(sockaddr*)&clientAddress,&addrlen))==INVALID_SOCKET){
    cout<<"接受客户端连接失败!";
    Sleep(3000);
    exit(-1);
    }
    cout<<"Accept connection from "<<inet_ntoa(clientAddress.sin_addr)<<endl;
    return clientSocket;
    }

    //发送数据
    void SendMsg(SOCKET &clientSocket,FileLog &fileLog)
    {
    char buf[2048];
    while(1){
    cout<<"服务器说:";
    gets_s(buf);
    if(send(clientSocket,buf,strlen(buf),0)==SOCKET_ERROR){
    cout<<"发送数据失败!"<<endl;
    Sleep(3000);
    exit(-1);
    }
    fileLog.Write("服务器 ").WriteLine(GetDate("%Y-%m-%d %H:%M:%S").c_str()).WriteLine(buf);//记录聊天内容
    }
    }


    int main(int argc, char* argv[]){
    WSADATA wsa;//WSADATA结构被用来保存函数WSAStartup返回的Windows Sockets初始化信息

    //MAKEWORD(a,b)是将两个byte型合并成一个word型,一个在高8位(b),一个在低8位(a)
    if(WSAStartup(MAKEWORD(2,2),&wsa)!=0){
    cout<<"套接字初始化失败!";
    Sleep(3000);
    exit(-1);
    }

    SOCKET serverSocket=StartServer();//启动服务器
    SOCKET clientSocket=ReceiveConnect(serverSocket);//接收客服端的链接

    FileLog fileLog;
    fileLog.Open(GetDate("%Y%m%d").append(".log").c_str());//打开记录聊天内容文件

    ReceiveStruct receiveStruct(&clientSocket,&fileLog);
    _beginthread(receive,0,&receiveStruct);//启动一个接收数据的线程

    SendMsg(clientSocket,fileLog);//发送数据

    fileLog.Close();//关闭文件
    closesocket(clientSocket);//关闭客户端套接字(马上发送FIN信号,所有没有接收到或是发送完成的数据都会丢失)
    closesocket(serverSocket);//关闭服务器套接字

    //清理套接字占用的资源
    WSACleanup();
    return0;
    }

      客户端代码:

       

    // Client.cpp  
    #include "stdafx.h"
    #include <windows.h>
    #include <process.h>
    #include <iostream>
    usingnamespace std;
    #pragma comment(lib,"ws2_32.lib")

    //接收数据
    void Receive(PVOID param)
    {
    char buf[2096];
    while(1)
    {
    SOCKET* sock=(SOCKET*)param;
    int bytes;
    if((bytes=recv(*sock,buf,sizeof(buf),0))==SOCKET_ERROR){
    printf("接收数据失败!\n");
    exit(-1);
    }
    buf[bytes]='\0';
    cout<<"服务器说:"<<buf<<endl;
    }
    }

    //获取服务器IP
    unsigned long GetServerIP(void)
    {
    //把字符串的IP地址转化为u_long
    char ipStr[20];
    //用第二个参数填充第一个参数所指的内存,填充的长度为第三个参数的大小
    memset(ipStr,0,sizeof(ipStr));
    cout<<"请输入你要链接的服务器IP:";
    cin>>ipStr;
    unsigned long ip;
    if((ip=inet_addr(ipStr))==INADDR_NONE){
    cout<<"不合法的IP地址:";
    Sleep(3000);
    exit(-1);
    }
    return ip;
    }

    //链接服务器
    void Connect(SOCKET &sock)
    {
    unsigned long ip=GetServerIP();
    //把端口号转化成整数
    short port=1986;
    cout<<"Connecting to "<<inet_ntoa(*(in_addr*)&ip)<<" : "<<port<<endl;
    struct sockaddr_in serverAddress;
    memset(&serverAddress,0,sizeof(sockaddr_in));
    serverAddress.sin_family=AF_INET;
    serverAddress.sin_addr.S_un.S_addr= ip;
    serverAddress.sin_port = htons(port);
    //建立和服务器的连接
    if(connect(sock,(sockaddr*)&serverAddress,sizeof(serverAddress))==SOCKET_ERROR){
    cout<<"建立连接失败:"<<WSAGetLastError();
    Sleep(3000);
    exit(-1);
    }
    }

    //发送数据
    void SendMsg(SOCKET &sock)
    {
    char buf[2048];
    while(1){

    //从控制台读取一行数据
    gets_s(buf);
    cout<<"我说:";
    //发送给服务器
    if(send(sock,buf,strlen(buf),0)==SOCKET_ERROR){
    cout<<"发送数据失败!";
    exit(-1);
    }
    }
    }

    int main(int argc, char* argv[]){
    WSADATA wsa;
    //初始化套接字DLL
    if(WSAStartup(MAKEWORD(2,2),&wsa)!=0){
    cout<<"套接字初始化失败!";
    Sleep(3000);
    exit(-1);
    }

    //创建套接字
    SOCKET sock;
    if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET){
    cout<<"创建套接字失败!";
    exit(-1);
    }

    Connect(sock);//链接服务器

    _beginthread(Receive,0,&sock);//启动接收数据线程
    SendMsg(sock);//发送数据

    //清理套接字占用的资源
    WSACleanup();
    return0;
    }

      文件操作代码(FileLog.h):

       

    #include "iostream"
    #include "string.h"
    #include <windows.h>
    usingnamespace std;

    class FileLog
    {
    private:
    CRITICAL_SECTION cs;
    HANDLE fileHandle;
    void Lock()
    {
    EnterCriticalSection(&cs);// 进入临界区
    }

    void UnLock()
    {
    LeaveCriticalSection(&cs);//离开临界区
    }

    public:
    FileLog()
    {
    InitializeCriticalSection(&cs);//初始化临界区
    fileHandle=INVALID_HANDLE_VALUE;//先初始化为错误的句柄
    }

    ~FileLog()
    {
    if(fileHandle!=INVALID_HANDLE_VALUE)
    {
    //CloseHandle的功能是关闭一个打开的对象句柄,该对象句柄可以是线程句柄,也可以是进程、信号量等其他内核对象的句柄
    CloseHandle(fileHandle);
    }
    DeleteCriticalSection(&cs);//删除临界区
    }

    BOOL Open(constchar*fileName);//打开文件
    FileLog& Write(constchar*content);//向文件中写入内容
    FileLog& WriteLine(constchar*content);//向文件中写入内容
    BOOL Read(char*buf,int size);//读文件内容
    BOOL Close();//关闭文件
    };

      文件操作代码(FileLog.app):

    #include "stdafx.h"
    #include "FileLog.h"
    //打开文件
    BOOL FileLog::Open(constchar*fileName)
    {
    if(fileHandle==INVALID_HANDLE_VALUE)
    {
    fileHandle=CreateFile(fileName,GENERIC_WRITE|GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,
    OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
    if(fileHandle!=INVALID_HANDLE_VALUE)
    {
    SetFilePointer(fileHandle,0,NULL,FILE_END);
    return TRUE;
    }
    }
    return FALSE;
    }

    //写文件 返回当前对象的引用,实现连接操作
    FileLog& FileLog::Write(constchar*content)
    {
    Lock();
    if(fileHandle!=INVALID_HANDLE_VALUE)
    {
    DWORD dwSize=0;
    WriteFile(fileHandle,content,strlen(content),&dwSize,NULL);//写
    }
    //开始的时候少写了这句,由于加的锁没有释放,一个线程占用之后,导致其他线程只能一直等待,好久都没有找到原因。
    UnLock();
    return*this;
    }

    //写入一行
    FileLog& FileLog::WriteLine(constchar*content)
    {
    Lock();
    if(fileHandle!=INVALID_HANDLE_VALUE)
    {
    DWORD dwSize=0;
    WriteFile(fileHandle,content,strlen(content),&dwSize,NULL);//写
    }
    UnLock();
    return FileLog::Write("\r\n");
    }

    //读文件内容
    BOOL FileLog::Read(char*buf,int size)
    {
    BOOL isOK=FALSE;
    Lock();
    if(fileHandle!=INVALID_HANDLE_VALUE)
    {
    DWORD dwSize=0;
    isOK=ReadFile(fileHandle,buf,size,&dwSize,NULL);//读
    }
    return isOK;
    }

    //关闭文件
    BOOL FileLog::Close()
    {
    BOOL isOK=FALSE;
    Lock();
    if(fileHandle!=INVALID_HANDLE_VALUE)
    {
    isOK=CloseHandle(fileHandle);
    fileHandle=INVALID_HANDLE_VALUE;
    }
    UnLock();
    return isOK;
    }
  • 相关阅读:
    nginx Server names
    ES6--变量的声明及解构赋值
    Android ListView and Tips.
    Eclipse自己定义keystore
    POJ 1129 Channel Allocation(DFS)
    机器学习笔记十三:Ensemble思想(上)
    设计模式——享元模式具体解释
    老猪带你玩转自定义控件三——sai大神带我实现ios 8 时间滚轮控件
    老猪带你玩转android自定义控件二——自定义索引栏listview
    android动手写控件系列——老猪叫你写相机
  • 原文地址:https://www.cnblogs.com/flyingspark/p/2397784.html
Copyright © 2020-2023  润新知