C++网络编程(一)
来源:互联网 发布:淘宝买家金钻好处 编辑:程序博客网 时间:2024/04/30 12:16
学习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/
我的博客目录
阅读全文
0 0
- Linux C语言 网络编程(一)
- 学习Linux C编程之网络编程(一)
- 【Java网络编程一】一个简单的c/s程序
- linux C语言网络编程学习总结< 一>
- C语言之网络编程(一)域名解析
- C#.NET网络程序开发的基本类(一)(C#---网络编程)
- 网络编程一:网络请求
- Windows网络编程一
- Linux网络编程(一)
- C#网络编程(一)
- 网络编程技术(一)
- 网络编程 一
- 网络编程学习(一)
- 网络编程一
- 网络编程 一
- 网络编程(一)
- Java网络编程(一)
- 网络编程(一)
- 标签二值化LabelBinarizer
- 关于activity,context那些坑
- Android RecyclerView 使用完全解析 体验艺术般的控件
- jmockit测试
- 4697: CFNetwork internal error (0xc01a:/XXX/CFNetwork-811.4.18/Loading/URLConnectionLoader.cpp:304)
- C++网络编程(一)
- 音视频同步(播放)原理
- 设计模式原则(5)--Law of Demeter(LoD)--迪米特法则
- UGUI 整页滑动
- hdu 2476 String painter
- spring cloud-实现Eureka注册中心的HA
- LintCode:M-房屋染色
- ZA7783:MIPI转LVDS/MIPI转RGB888/RGB转LVDS
- Ubuntu 16.04 下 Vim安装及配置