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

相信在不远处有一家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);//记录聊天内容    }}

//获取本机IPin_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);    }

//获取服务器IPstruct 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;    }}

//获取服务器IPunsigned long GetServerIP(void){//把字符串的IP地址转化为u_longchar 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;//初始化套接字DLLif(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;}

作者:陈太汉

博客:http://www.cnblogs.com/hlxs/

转载于:https://www.cnblogs.com/hlxs/archive/2011/09/09/2172351.html

C++网络编程(一)相关推荐

  1. Linux网络编程--进程间通信(一)

    进程间通信简介(摘自<Linux网络编程>p85) AT&T 在 UNIX System V 中引入了几种新的进程通讯方式,即消息队列( MessageQueues),信号量( s ...

  2. C#_Socket网络编程实现的简单局域网内即时聊天,发送文件,抖动窗口。

    C#_Socket网络编程实现的简单局域网内即时聊天,发送文件,抖动窗口. 最近接触了C#Socket网络编程,试着做了试试(*^__^*) 实现多个客户端和服务端互相发送消息 发送文件 抖动窗口功能 ...

  3. java基于http协议编程_Java中基于HTTP协议网络编程

    java中为我们的网络支持提供了java.net包,能够使我们以编程的方式来访问Web服务功能,这篇博客,就跟大家分享一下,Java中的网络编程的知识,主要是学习下该java.net包下的API. U ...

  4. java 密钥工厂 desede_20145212 实验五《Java网络编程》

    20145212 实验五<Java网络编程> 一.实验内容1.运行下载的TCP代码,结对进行,一人服务器,一人客户端: 2.利用加解密代码包,编译运行代码,一人加密,一人解密: 3.集成代 ...

  5. Linux io模型及函数调用,Linux 网络编程的5种IO模型:信号驱动IO模型

    Linux 网络编程的5种IO模型:信号驱动IO模型 背景 这一讲我们来看 信号驱动IO 模型. 介绍 情景引入: 在信号驱动IO模型中,当用户线程发起一个IO请求操作,会给对应的socket注册一个 ...

  6. android 网络编程实现,Android开发使用HttpURLConnection进行网络编程详解【附源码下载】...

    本文实例讲述了Android开发使用HttpURLConnection进行网络编程.分享给大家供大家参考,具体如下: --HttpURLConnection URLConnection已经可以非常方便 ...

  7. Linux网络编程实例分析

    最近由于工作原因需要温习一下Linux网络编程的部分基础知识,因此对之前写的Socket网络通信的代码进行了进一步优化和拓展,在不关闭一次Socket连接的基础上,对服务端加入循环读写的功能,同时加入 ...

  8. C语言网络编程:多路IO select实现多客户端

    文章目录 阻塞式的服务器程序 多线程服务器程序 非阻塞式服务器程序 基于事件响应的服务器程序 事件响应服务器程序的实现`select` 阻塞式的服务器程序 我们接触过最多的最基础的网络通信模型为TCP ...

  9. C语言网络编程:close或者shutdown断开通信连接

    文章目录 前言 close函数介绍 shutdown函数介绍 前言 这里在主要通过实例进行描述close函数在网络编程中的使用 TCP编程模型中客户端或者服务器只要主动通过close发起断开连接的请求 ...

  10. Android网络编程系列 一 Socket抽象层

    在<Android网络编程>系列文章中,前面已经将Java的通信底层大致的描述了,在我们了解了TCP/IP通信族架构及其原理,接下来我们就开始来了解基于tcp/ip协议层的Socket抽象 ...

最新文章

  1. Qt 如何消除边框 及 实现透明底色
  2. 辗转相除法求多项式的最大公因式
  3. Count Color poj2777 线段树
  4. J2ee eclipse中配置 本地配置的maven
  5. verilator编译 更新文件的规则
  6. Listary 高效启动器(win)
  7. 初识UNIX操作系统
  8. linux grep -rn如何只过滤第二层的某个文件夹
  9. 解决SVN造成的桌面图标问号
  10. 在线文档 - Google 文档的数据协议设计
  11. Android系统体系结构
  12. MongoDB文件服务器搭建
  13. 尼尔森报告指出,宅经济成快速消费品在农历新年的商机
  14. STM32的DS18B20驱动
  15. java web网上商城项目实战与源码
  16. BIM二级考试第17期第一题用revit2016系统库中现场浇筑楼梯平台的bug
  17. jQuery实现导航栏的样式切换
  18. USB Mass Storage协议
  19. ROS中实现A*路径规划
  20. windows录音及MP3合成

热门文章

  1. 大赛归来的你们,依然青春少年
  2. python 分词包_NLP相关python包
  3. c语言程序设计文件操作,c语言程序设计文件操作方法示例(CreateFile和fopen)
  4. 武汉大学计算机学院 毕业答辩,“云答辩”详细流程出炉! 武大本科生毕业答辩这样办...
  5. oracle执行长任务,oracle 里面定时执行任务设置
  6. python os.path.join乱码_python os.listdir()乱码解决方案
  7. java web 初始化方法_Java Web(二) 类的初始化及初始化顺序
  8. 关于I2C协议和SPI协议学习之中的补充修改
  9. mysql表收缩时从库也收缩么_收缩数据库 - SQL Server | Microsoft Docs
  10. 伸展树算法c语言,数据结构伸展树介绍及C语言的实现方法