C++ 网络编程实例

来源:https://www.cnblogs.com/jeffkuang/archive/2011/11/25/2263051.html

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

 

简 单介绍:他实现了点对点聊天,一个服务器,一个客户端,主线程用来发送数据,启动一个子线程用来接收数据,服务器记录聊天内容。他只是用上了上面所说的三 个技术,如果你对上面三个技术不是很熟,或许对你有点帮助,如果你很熟,既然来了希望你能指导一下我,如果你是高手希望你能指导一下我的编码问题。我太渴 望写出高效简洁的代码。

服务器代码:

// Server.cpp : 定义控制台应用程序的入口点。
 
#include "stdafx.h"
#include <windows.h>
#include <process.h>
#include <iostream>
#include "FileLog.h"
#include "time.h"
using namespace 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(const char *format)
{
    time_t tm;
    struct tm *now;
    char timebuf[20];
    time(&tm);
    now=localtime(&tm);
    strftime(timebuf,sizeof(timebuf)/sizeof(char),format,now);
    return string(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();
    return 0;
} 

客户端代码:

// Client.cpp  
#include "stdafx.h"
#include <windows.h>
#include <process.h>
#include <iostream>
using namespace 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();
    return 0;
} 

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

#include "iostream"
#include "string.h"
#include <windows.h>
using namespace 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(const char *fileName);//打开文件
        FileLog& Write(const char *content);//向文件中写入内容
        FileLog& WriteLine(const char *content);//向文件中写入内容
        BOOL Read(char *buf,int size);//读文件内容
        BOOL Close();//关闭文件
};

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

#include "stdafx.h"
#include "FileLog.h"
//打开文件
BOOL FileLog::Open(const char *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(const char *content)
{
    Lock();
    if(fileHandle!=INVALID_HANDLE_VALUE)
    {
        DWORD dwSize=0;
        WriteFile(fileHandle,content,strlen(content),&dwSize,NULL);//写
    }
    //开始的时候少写了这句,由于加的锁没有释放,一个线程占用之后,导致其他线程只能一直等待,好久都没有找到原因。
    UnLock();   
    return *this;
} 

//写入一行
FileLog& FileLog::WriteLine(const char *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;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值