C++一个网络编程实例

C++一个网络编程实例

学习C++已经有一段时间了,一直都是学习基础的东西,每次写的代码都比较少,没有明确的学习目标,基础还是基础,漫无边际的,基本上都是做一道或者几道算法题,连一个小小的实战都没有,也不知道自己学得怎么样了,现在终于有一个小小的实战了《C++ 一个网络编程实例》。

    学习C++已经有一段时间了,一直都是学习基础的东西,每次写的代码都比较少,没有明确的学习目标,基础还是基础,漫无边际的,基本上都是做一道或者几道算法题,连一个小小的实战都没有,也不知道自己学得怎么样了,现在终于有一个小小的实战了《C++ 一个网络编程实例》。由于自己一直在做C#,只能业余时间学习C++,都说C++ 是那么的难,暂时还没有感觉到有多难,毕竟写代码也有两年多了。我要学习多久才能进一家做C++研发的公司呢?

    相信在不远处有一家C++研发公司在等着我。

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

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

    废话就少说了,程序里处处都是注释,你可以选择看看我的代码,或是选择直接运行看看。

    服务器代码:

       
       
    1. // Server.cpp : 定义控制台应用程序的入口点。  
    2.    
    3. #include "stdafx.h"  
    4. #include <windows.h>  
    5. #include <process.h>  
    6. #include <iostream>  
    7. #include "FileLog.h"  
    8. #include "time.h"  
    9. using namespace std;  
    10. #pragma comment(lib,"ws2_32.lib")  
    11.  
    12. //多线程调用的方法只有一个指针型的参数,有时候需要多个参数,所以定义一个结构,参数作为结构的字段  
    13. typedef struct _receiveStruct  
    14. {  
    15.     SOCKET *Socket;  
    16.     FileLog *fileLog;  
    17.     _receiveStruct(SOCKET *_socket,FileLog *_fileLog):Socket(_socket),fileLog(_fileLog){}  
    18. } ReceiveStruct;  
    19.  
    20. //获取今天日期的字符串  
    21. string GetDate(const char *format)  
    22. {  
    23.     time_t tm;  
    24.     struct tm *now;  
    25.     char timebuf[20];  
    26.     time(&tm);  
    27.     now=localtime(&tm);  
    28.     strftime(timebuf,sizeof(timebuf)/sizeof(char),format,now);  
    29.     return string(timebuf);  
    30. }  
    31.  
    32. //接收数据线程  
    33. void receive(PVOID param)  
    34. {  
    35.     ReceiveStruct* receiveStruct=(ReceiveStruct*)param;  
    36.     char buf[2048];  
    37.     int bytes;  
    38.     while(1)  
    39.     {  
    40.         //接收数据  
    41.         if((bytes=recv(*receiveStruct->Socket,buf,sizeof(buf),0))==SOCKET_ERROR){  
    42.             cout<<"接收数据失败!\n";  
    43.             _endthread();//终止当前线程  
    44.         }  
    45.         buf[bytes]='\0';  
    46.         cout<<"客户端说:"<<buf<<endl;  
    47.         receiveStruct->fileLog->Write("客户端    ").WriteLine(GetDate("%Y-%m-%d %H:%M:%S").c_str()).WriteLine(buf);//记录聊天内容  
    48.     }  
    49. }  
    50.  
    51.  
    52. //获取本机IP  
    53. in_addr getHostName(void)   
    54. {  
    55.     char host_name[255];  
    56.     //获取本地主机名称  
    57.     if (gethostname(host_name, sizeof(host_name)) == SOCKET_ERROR) {  
    58.         cout<<"Error %d when getting local host name."<<WSAGetLastError();  
    59.         Sleep(3000);  
    60.         exit(-1);  
    61.     }  
    62.       
    63.     //从主机名数据库中得到对应的“IP”   
    64.     struct hostent *phe = gethostbyname(host_name);  
    65.     if (phe == 0) {  
    66.         cout<<"Yow! Bad host lookup.";  
    67.         Sleep(3000);  
    68.         exit(-1);  
    69.     }  
    70.  
    71.     struct in_addr addr;  
    72.     memcpy(&addr, phe->h_addr_list[0], sizeof(struct in_addr));  
    73.     return addr;   
    74. }  
    75.  
    76.  
    77. //启动服务器  
    78. SOCKET StartServer(void)  
    79. {  
    80.     //创建套接字  
    81.     SOCKET serverSocket;  
    82.     if((serverSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET){  
    83.         cout<<"创建套接字失败!";  
    84.         Sleep(3000);  
    85.         exit(-1);  
    86.     }  
    87.     short port=1986;  
    88.     struct sockaddr_in serverAddress;  
    89.     //初始化指定的内存区域  
    90.     memset(&serverAddress,0,sizeof(sockaddr_in));  
    91.     serverAddress.sin_family=AF_INET;  
    92.     serverAddress.sin_addr.S_un.S_addr = htonl(INADDR_ANY);  
    93.     serverAddress.sin_port = htons(port);  
    94.  
    95.     //绑定  
    96.     if(bind(serverSocket,(sockaddr*)&serverAddress,sizeof(serverAddress))==SOCKET_ERROR){  
    97.         cout<<"套接字绑定到端口失败!端口:"<<port;  
    98.         Sleep(3000);  
    99.         exit(-1);  
    100.     }  
    101.  
    102.     //进入侦听状态  
    103.     if(listen(serverSocket,SOMAXCONN)==SOCKET_ERROR){  
    104.         cout<<"侦听失败!";  
    105.         Sleep(3000);  
    106.         exit(-1);  
    107.     }  
    108.        
    109.     //获取服务器IP  
    110.     struct in_addr addr = getHostName();   
    111.     cout<<"Server "<<inet_ntoa(addr)<<" : "<<port<<" is listening......"<<endl;  
    112.     return serverSocket;  
    113. }  
    114.  
    115.  
    116. //接收客户端连接  
    117. SOCKET ReceiveConnect(SOCKET &serverSocket)  
    118. {  
    119.     SOCKET clientSocket;//用来和客户端通信的套接字  
    120.     struct sockaddr_in clientAddress;//用来和客户端通信的套接字地址  
    121.     memset(&clientAddress,0,sizeof(clientAddress));//初始化存放客户端信息的内存  
    122.     int addrlen = sizeof(clientAddress);  
    123.        
    124.     //接受连接  
    125.     if((clientSocket=accept(serverSocket,(sockaddr*)&clientAddress,&addrlen))==INVALID_SOCKET){  
    126.         cout<<"接受客户端连接失败!";  
    127.         Sleep(3000);  
    128.         exit(-1);  
    129.     }  
    130.      cout<<"Accept connection from "<<inet_ntoa(clientAddress.sin_addr)<<endl;  
    131.     return clientSocket;  
    132. }  
    133.  
    134.  
    135. //发送数据  
    136. void SendMsg(SOCKET &clientSocket,FileLog &fileLog)  
    137. {  
    138.     char buf[2048];  
    139.     while(1){  
    140.         cout<<"服务器说:";  
    141.         gets_s(buf);  
    142.         if(send(clientSocket,buf,strlen(buf),0)==SOCKET_ERROR){  
    143.             cout<<"发送数据失败!"<<endl;  
    144.             Sleep(3000);  
    145.             exit(-1);  
    146.         }  
    147.         fileLog.Write("服务器   ").WriteLine(GetDate("%Y-%m-%d %H:%M:%S").c_str()).WriteLine(buf);//记录聊天内容  
    148.     }  
    149. }  
    150.     
    151.  
    152. int main(int argc, char* argv[]){  
    153.     WSADATA wsa;//WSADATA结构被用来保存函数WSAStartup返回的Windows Sockets初始化信息  
    154.    
    155.     //MAKEWORD(a,b)是将两个byte型合并成一个word型,一个在高8位(b),一个在低8位(a)   
    156.     if(WSAStartup(MAKEWORD(2,2),&wsa)!=0){  
    157.         cout<<"套接字初始化失败!";  
    158.         Sleep(3000);  
    159.         exit(-1);  
    160.     }  
    161.       
    162.     SOCKET serverSocket=StartServer();//启动服务器  
    163.     SOCKET clientSocket=ReceiveConnect(serverSocket);//接收客服端的链接  
    164.      
    165.     FileLog fileLog;  
    166.     fileLog.Open(GetDate("%Y%m%d").append(".log").c_str());//打开记录聊天内容文件  
    167.    
    168.     ReceiveStruct receiveStruct(&clientSocket,&fileLog);  
    169.     _beginthread(receive,0,&receiveStruct);//启动一个接收数据的线程  
    170.    
    171.     SendMsg(clientSocket,fileLog);//发送数据  
    172.  
    173.     fileLog.Close();//关闭文件  
    174.     closesocket(clientSocket);//关闭客户端套接字(马上发送FIN信号,所有没有接收到或是发送完成的数据都会丢失)  
    175.     closesocket(serverSocket);//关闭服务器套接字  
    176.         
    177.     //清理套接字占用的资源  
    178.     WSACleanup();  
    179.     return 0;  
    180. }  

     客户端代码:

       
       
    1. // Client.cpp    
    2. #include "stdafx.h"  
    3. #include <windows.h>  
    4. #include <process.h>  
    5. #include <iostream>  
    6. using namespace std;  
    7. #pragma comment(lib,"ws2_32.lib")  
    8.  
    9. //接收数据  
    10. void Receive(PVOID param)  
    11. {  
    12.     char buf[2096];  
    13.     while(1)  
    14.     {  
    15.         SOCKET* sock=(SOCKET*)param;  
    16.         int bytes;  
    17.         if((bytes=recv(*sock,buf,sizeof(buf),0))==SOCKET_ERROR){  
    18.             printf("接收数据失败!\n");  
    19.             exit(-1);  
    20.         }  
    21.         buf[bytes]='\0';  
    22.         cout<<"服务器说:"<<buf<<endl;  
    23.     }  
    24. }  
    25.  
    26. //获取服务器IP  
    27. unsigned long GetServerIP(void)  
    28. {  
    29.     //把字符串的IP地址转化为u_long  
    30.     char ipStr[20];  
    31.     //用第二个参数填充第一个参数所指的内存,填充的长度为第三个参数的大小  
    32.     memset(ipStr,0,sizeof(ipStr));  
    33.     cout<<"请输入你要链接的服务器IP:";  
    34.     cin>>ipStr;  
    35.     unsigned long ip;  
    36.     if((ip=inet_addr(ipStr))==INADDR_NONE){  
    37.         cout<<"不合法的IP地址:";  
    38.         Sleep(3000);  
    39.         exit(-1);  
    40.     }  
    41.     return ip;  
    42. }  
    43.  
    44. //链接服务器  
    45. void Connect(SOCKET &sock)  
    46. {  
    47.     unsigned long ip=GetServerIP();  
    48.     //把端口号转化成整数  
    49.     short port=1986;  
    50.     cout<<"Connecting to "<<inet_ntoa(*(in_addr*)&ip)<<" : "<<port<<endl;  
    51.     struct sockaddr_in serverAddress;  
    52.     memset(&serverAddress,0,sizeof(sockaddr_in));  
    53.     serverAddress.sin_family=AF_INET;  
    54.     serverAddress.sin_addr.S_un.S_addr= ip;  
    55.     serverAddress.sin_port = htons(port);  
    56.     //建立和服务器的连接  
    57.     if(connect(sock,(sockaddr*)&serverAddress,sizeof(serverAddress))==SOCKET_ERROR){  
    58.         cout<<"建立连接失败:"<<WSAGetLastError();   
    59.         Sleep(3000);  
    60.         exit(-1);  
    61.     }  
    62. }  
    63.  
    64. //发送数据  
    65. void SendMsg(SOCKET &sock)  
    66. {  
    67.     char buf[2048];  
    68.     while(1){  
    69.           
    70.         //从控制台读取一行数据  
    71.         gets_s(buf);  
    72.         cout<<"我说:";  
    73.         //发送给服务器  
    74.         if(send(sock,buf,strlen(buf),0)==SOCKET_ERROR){  
    75.             cout<<"发送数据失败!";  
    76.             exit(-1);  
    77.         }  
    78.     }  
    79. }  
    80.  
    81. int main(int argc, char* argv[]){  
    82.     WSADATA wsa;  
    83.     //初始化套接字DLL  
    84.     if(WSAStartup(MAKEWORD(2,2),&wsa)!=0){  
    85.         cout<<"套接字初始化失败!";  
    86.         Sleep(3000);  
    87.         exit(-1);  
    88.     }  
    89.     
    90.     //创建套接字  
    91.     SOCKET sock;  
    92.     if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET){  
    93.         cout<<"创建套接字失败!";  
    94.         exit(-1);  
    95.     }  
    96.  
    97.     Connect(sock);//链接服务器  
    98.       
    99.     _beginthread(Receive,0,&sock);//启动接收数据线程  
    100.     SendMsg(sock);//发送数据  
    101.       
    102.     //清理套接字占用的资源  
    103.     WSACleanup();  
    104.     return 0;  
    105. }  

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

       
       
    1. #include "iostream"  
    2. #include "string.h"  
    3. #include <windows.h>  
    4. using namespace std;  
    5.  
    6. class FileLog  
    7. {  
    8.     private:  
    9.         CRITICAL_SECTION cs;  
    10.         HANDLE fileHandle;  
    11.         void Lock()  
    12.         {  
    13.             EnterCriticalSection(&cs);// 进入临界区  
    14.         }  
    15.  
    16.         void UnLock()  
    17.         {  
    18.             LeaveCriticalSection(&cs);//离开临界区  
    19.         }  
    20.  
    21.     public:  
    22.         FileLog()  
    23.         {  
    24.             InitializeCriticalSection(&cs);//初始化临界区  
    25.             fileHandle=INVALID_HANDLE_VALUE;//先初始化为错误的句柄  
    26.         }  
    27.  
    28.         ~FileLog()  
    29.         {  
    30.             if(fileHandle!=INVALID_HANDLE_VALUE)  
    31.             {  
    32.                 //CloseHandle的功能是关闭一个打开的对象句柄,该对象句柄可以是线程句柄,也可以是进程、信号量等其他内核对象的句柄  
    33.                 CloseHandle(fileHandle);  
    34.             }  
    35.             DeleteCriticalSection(&cs);//删除临界区  
    36.         }  
    37.    
    38.         BOOL Open(const char *fileName);//打开文件  
    39.         FileLog& Write(const char *content);//向文件中写入内容  
    40.         FileLog& WriteLine(const char *content);//向文件中写入内容  
    41.         BOOL Read(char *buf,int size);//读文件内容  
    42.         BOOL Close();//关闭文件  
    43. }; 

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

       
       
    1. #include "stdafx.h"  
    2. #include "FileLog.h"  
    3. //打开文件  
    4. BOOL FileLog::Open(const char *fileName)  
    5. {  
    6.     if(fileHandle==INVALID_HANDLE_VALUE)  
    7.     {  
    8.         fileHandle=CreateFile(fileName,GENERIC_WRITE|GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,  
    9.             OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);  
    10.         if(fileHandle!=INVALID_HANDLE_VALUE)  
    11.         {  
    12.             SetFilePointer(fileHandle,0,NULL,FILE_END);   
    13.             return TRUE;  
    14.         }  
    15.     }  
    16.     return FALSE;  
    17. }  
    18.  
    19. //写文件 返回当前对象的引用,实现连接操作  
    20. FileLog& FileLog::Write(const char *content)  
    21. {  
    22.     Lock();  
    23.     if(fileHandle!=INVALID_HANDLE_VALUE)  
    24.     {  
    25.         DWORD dwSize=0;  
    26.         WriteFile(fileHandle,content,strlen(content),&dwSize,NULL);//写  
    27.     }  
    28.     //开始的时候少写了这句,由于加的锁没有释放,一个线程占用之后,导致其他线程只能一直等待,好久都没有找到原因。  
    29.     UnLock();     
    30.     return *this;  
    31. }   
    32.  
    33. //写入一行  
    34. FileLog& FileLog::WriteLine(const char *content)  
    35. {  
    36.     Lock();  
    37.     if(fileHandle!=INVALID_HANDLE_VALUE)  
    38.     {  
    39.         DWORD dwSize=0;  
    40.         WriteFile(fileHandle,content,strlen(content),&dwSize,NULL);//写  
    41.     }  
    42.     UnLock();  
    43.     return FileLog::Write("\r\n");  
    44. }   
    45.  
    46. //读文件内容  
    47. BOOL FileLog::Read(char *buf,int size)  
    48. {  
    49.     BOOL isOK=FALSE;  
    50.     Lock();  
    51.     if(fileHandle!=INVALID_HANDLE_VALUE)  
    52.     {  
    53.         DWORD dwSize=0;  
    54.         isOK=ReadFile(fileHandle,buf,size,&dwSize,NULL);//读  
    55.     }  
    56.     return isOK;  
    57. }  
    58.  
    59. //关闭文件  
    60. BOOL FileLog::Close()   
    61. {  
    62.     BOOL isOK=FALSE;  
    63.     Lock();  
    64.     if(fileHandle!=INVALID_HANDLE_VALUE)  
    65.     {  
    66.         isOK=CloseHandle(fileHandle);  
    67.         fileHandle=INVALID_HANDLE_VALUE;  
    68.     }  
    69.     UnLock();  
    70.     return isOK;  
    71. }  
    72.   

    作者:陈太汉
    博客:http://www.cnblogs.com/hlxs/

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

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

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

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值