c++java编程思想java编程思想

不积跬步无以至千里,不积小流无以成江海。
C++网络编程
1. TCP与UDP的比较
TCP是面向连接的,交互双方的进程各自建立一个流式套接字,服务器需要等待客户端向其提出连接申请。一旦接受客户端申请就立刻返回一个新的套接字描述符。通过该描述符调用数据传输函数与客户端进行数据的收发。
UDP是面向无连接的,双方建立的是数据报套接字,服务器和客户端在进行传描数据之前不需要进行连接的申请和建立,可以随时向对方发消息。
优点:可靠、稳定
缺点:速度慢,效率低、占用系统资源高、易被攻击。
适合场景:网络通讯质量要求高(可靠、稳定)
优点:速度快,比TCP稍安全
缺点:不可靠、不稳定
适用场合:网络通讯质量要求不高,速度快。
2. Socket粘包问题
什么时候需要考虑粘包问题
1:如果利用tcp每次发送数据,就与对方建立连接,然后双方发送完一段数据后,就关闭连接,这样就不会出现粘包问题(因为只有一种包结构,类似于http协议)。关闭连接主要要双方都发送close连接(参考tcp关闭协议)。如:A需要发送一段字符串给B,那么A与B建立连接,然后发送双方都默认好的协议字符如"hello give me sth abour yourself",然后B收到报文后,就将缓冲区数据接收,然后关闭连接,这样粘包问题不用考虑到,因为大家都知道是发送一段字符;
2:如果发送数据无结构,如文件传输,这样发送方只管发送,接收方只管接收存储就ok,也不用考虑粘包;
3:如果双方建立连接,需要在连接后一段时间内发送不同结构数据,如连接后,有好几种结构:
1)"hellogive me sth abour yourself"
2)"Don'tgive me sth abour yourself"
那这样的话,如果发送方连续发送这个两个包出去,接收方一次接收可能会是"hello give me sth abour yourselfDon't give me sth abouryourself" 这样接收方就傻了,到底是要干嘛?不知道,因为协议没有规定这么诡异的字符串,所以要处理把它分包,怎么分也需要双方组织一个比较好的包结构,所以一般可能会在头加一个数据长度之类的包,以确保接收。
粘包出现原因:
在流传输中出现,UDP不会出现粘包,因为它有消息保护边界。
1 发送端需要等缓冲区满才发送出去,造成粘包
2 接收方不及时接收缓冲区的包,造成多个包接收
解决办法:
为了避免粘包现象,可采取以下几种措施:
一是对于发送方引起的粘包现象,用户可通过编程设置来避免,TCP提供了强制数据立即传送的操作指令push,TCP软件收到该操作指令后,就立即将本段数据发送出去,而不必等待发送缓冲区满;
二是对于接收方引起的粘包,则可通过优化程序设计、精简接收进程工作量、提高接收进程优先级等措施,使其及时接收数据,从而尽量避免出现粘包现象;
三是由接收方控制,将一包数据按结构字段,人为控制分多次接收,然后合并,通过这种手段来避免粘包。
以上提到的三种措施,都有其不足之处。
第一种编程设置方法虽然可以避免发送方引起的粘包,但它关闭了优化算法,降低了网络发送效率,影响应用程序的性能,一般不建议使用。
第二种方法只能减少出现粘包的可能性,但并不能完全避免粘包,当发送频率较高时,或由于网络突发可能使某个时间段数据包到达接收方较快,接收方还是有可能来不及接收,从而导致粘包。
第三种方法虽然避免了粘包,但应用程序的效率较低,对实时应用的场合不适合。
更为简洁的说法:
包尾加\r\n
包头加包体长度
网上说法:
个人比较喜欢的一种做法是给一帧数据加帧头帧尾,然后接收方不断接受并缓存收到的数据,根据帧头帧尾分离出一帧完整的数据,再分离各字段得到数据。
如果某个包出错了,怎么不断恢复?
发送消息时,每个消息长度在编程的时候就指定了。如果接收到的数据包有问题,我们可以通过消息长度来不断回复原来的数据包。
3. TCP例子
&WinSock2.h&
comment(lib,
"ws2_32.lib")
_tmain(int argc,
_TCHAR* argv[])
WSADATA wsaD
int port = 5099;
char buf[] =
"服务器: 欢迎登录......\n";
// 加载套接字
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
printf("加载套接字失败:%d......\n", WSAGetLastError());
// socket()
SOCKET sockSrv = socket(AF_INET,
SOCK_STREAM, 0);
// 初始化IP和端口信息
SOCKADDR_IN addrS
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(port); // 1024以上的端口号
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
if (bind(sockSrv, (LPSOCKADDR)&addrSrv,
sizeof(SOCKADDR_IN)) ==
SOCKET_ERROR)
printf("套接字绑定失败:%d......\n", WSAGetLastError());
// listen()
if (listen(sockSrv, 10) ==
SOCKET_ERROR){
printf("套接字监听失败:%d......\n", WSAGetLastError());
// 客户端信息
SOCKADDR_IN addrC
sizeof(SOCKADDR);
// 开始监听
printf("服务端启动成功......开始监听...\n");
// 等待客户请求到来
SOCKET sockConn = accept(sockSrv, (SOCKADDR *)&addrClient, &len);
if (sockConn ==
SOCKET_ERROR){
printf("建立连接失败:%d......\n", WSAGetLastError());
printf("与客户端建立连接......IP:[%s]\n", inet_ntoa(addrClient.sin_addr));
// 发送数据
if (send(sockConn, buf,
sizeof(buf), 0) == SOCKET_ERROR){
printf("发送数据失败......\n");
char recvBuf[100];
memset(recvBuf, 0, sizeof(recvBuf));
// 接收数据
recv(sockConn, recvBuf, sizeof(recvBuf), 0);
printf("收到数据:%s\n", recvBuf);
closesocket(sockConn);
// 关闭套接字
closesocket(sockSrv);
WSACleanup();
system("pause");
&WinSock2.h&
comment(lib,
"ws2_32.lib")
_tmain(int argc,
_TCHAR* argv[])
WSADATA wsaD
int port = 5099;
char buff[1024];
memset(buff, 0, sizeof(buff));
// 加载套接字
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
printf("加载套接字失败:%d......\n", WSAGetLastError());
// 初始化IP和端口信息
SOCKADDR_IN addrS
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(port);
addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
// socket()
SOCKET sockClient = socket(AF_INET,
SOCK_STREAM, 0);
if (SOCKET_ERROR == sockClient){
printf("创建套接字失败:%d......\n", WSAGetLastError());
// 向服务器发出连接请求
if (connect(sockClient, (struct
sockaddr*)&addrSrv,
sizeof(addrSrv)) == INVALID_SOCKET)
printf("连接服务器失败:%d......\n", WSAGetLastError());
// 接收数据
recv(sockClient, buff, sizeof(buff), 0);
printf("收到数据:%s\n", buff);
// 发送数据
char buf[] =
"客户端:请求登录......";
send(sockClient, buf, sizeof(buf), 0);
// 关闭套接字
closesocket(sockClient);
WSACleanup();
旧函数解决方式:
4. UDP例子
服务端(接收方):
// UDPReceiverTest.cpp : 定义控制台应用程序的入口点。
"stdafx.h"
&WinSock2.h&
comment(lib,
"ws2_32.lib")
_tmain(int argc,
_TCHAR* argv[])
WSADATA wsaD
int port = 5099;
// 加载套接字
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
printf("加载套接字失败:%d......\n", WSAGetLastError());
// 初始化IP和端口信息
SOCKADDR_IN addrS
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(port);
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
// socket()
SOCKET sockClient = socket(AF_INET,SOCK_DGRAM, 0);
if (SOCKET_ERROR == sockClient){
printf("创建套接字失败:%d......\n", WSAGetLastError());
if (bind(sockClient, (LPSOCKADDR)&addrSrv,
sizeof(SOCKADDR_IN)) ==
SOCKET_ERROR)
printf("套接字绑定失败:%d......\n", WSAGetLastError());
SOCKADDR_IN addrC
int nLen =
sizeof(SOCKADDR);
char szMsg[1024];
memset(szMsg, 0, sizeof(szMsg));
// 等待客户请求到来
printf("服务端启动成功......等待客户发送数据...\n");
// 接收数据
if (SOCKET_ERROR != recvfrom(sockClient, szMsg,
sizeof(szMsg), 0, (SOCKADDR*)&addrClnt, &nLen))
printf("发送方:%s\n", szMsg);
char szSrvMsg[] =
"收到...";
// 发送数据
sendto(sockClient, szSrvMsg,
sizeof(szSrvMsg), 0, (SOCKADDR*)&addrClnt, nLen);
// 上面为无线循环,以下代码不会执行
// 关闭套接字
closesocket(sockClient);
WSACleanup();
// UDPSenderTest.cpp : 定义控制台应用程序的入口点。
"stdafx.h"
&WinSock2.h&
comment(lib,
"ws2_32.lib")
_tmain(int argc,
_TCHAR* argv[])
WSADATA wsaD
int port = 5099;
// 加载套接字
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
printf("加载套接字失败:%d......\n", WSAGetLastError());
// socket()
SOCKET sockClient = socket(AF_INET,
SOCK_DGRAM, 0);
if (SOCKET_ERROR == sockClient){
printf("创建套接字失败:%d......\n", WSAGetLastError());
// 初始化IP和端口信息
SOCKADDR_IN addrS
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(port);
addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
int nLen =
sizeof(SOCKADDR);
// 发送数据
char szMsg[1024];
memset(szMsg, 0, sizeof(szMsg));
sendto(sockClient, szMsg, sizeof(szMsg), 0, (SOCKADDR*)&addrSrv, nLen);
// 发送数据
// 初始化数据
char szMsg[1024];
memset(szMsg, 0, sizeof(szMsg));
printf("请输入要发送的数据(输入q退出):");
scanf("%s", &szMsg);
// 退出循环
if (!strcmp(szMsg,
"q") || !strcmp(szMsg, "Q"))
// 发送数据
sendto(sockClient, szMsg, sizeof(szMsg), 0, (SOCKADDR*)&addrSrv, nLen);
// 清空缓存
memset(szMsg, 0, sizeof(szMsg));
// 接收数据
if (SOCKET_ERROR != recvfrom(sockClient, szMsg,
sizeof(szMsg), 0, (SOCKADDR*)&addrSrv, &nLen))
printf("接收方:%s\n", szMsg);
// 关闭套接字
closesocket(sockClient);
WSACleanup();
5. TCP和 UDP 注意点
易忽略,出错的地方:socket()
SOCKET sockClient = socket(AF_INET,
SOCK_STREAM, 0);
SOCKET sockClient = socket(AF_INET,
SOCK_DGRAM, 0);
TCP不存在数据边界:
收到数据不意味着马上调用read()函数,只要不超过数组容量,则有可能数据填充满缓冲后通过一次read()函数调用读取全部,也有可能分成多次read()函数调用进行读取。如果传输出错就会提供重传服务。(套接字内部有一个由字节数组构成的缓冲)
6. 结构体、图片传输方法
首先通讯双方需要统一结构体,示例:
char strMsg[64];
// 结构体消息
Massage stM
memset(stMsg.strMsg, 0, sizeof(stMsg.strMsg));
stMsg.nID = 1001;
strcpy(stMsg.strMsg, "Struct string");
sendto(sockClient, (char*)&stMsg,
sizeof(stMsg) + 1, 0, (SOCKADDR*)&addrClnt, nLen);
Massage stM
memset(stMsg.strMsg, 0, sizeof(stMsg.strMsg));
memcpy(&stMsg, szMsg, sizeof(stMsg) + 1);
printf("接收方:%d\t%s\n", stMsg.nID, stMsg.strMsg);
特别注意: sizeof(stMsg) + 1 两者必须保持一致。
拓展:发送文件
char buf[256];
memset(stPhoto.buf, 0, sizeof(stPhoto.buf));
// 发送文件
printf("正在发送文件......\n");
while (fp1)
// 读取文件内容到buf中,每次读256字节,返回值表示实际读取的字节数
int nCount = fread(stPhoto.buf, 1,
sizeof(stPhoto.buf), fp1);
stPhoto.nSize = nC
//printf("read %d byte\n", nCount);
// 如果读取的字节数不大于0,说明读取出错或文件已经读取完毕
if (nCount &= 0)
sprintf(stPhoto.buf,
"finish\n");
sendto(sockClient, (char*)&stPhoto,
sizeof(stPhoto), 0, (SOCKADDR*)&addrSrv, nLen);
printf("文件发送完成......\n");
sendto(sockClient, (char*)&stPhoto,
sizeof(stPhoto), 0, (SOCKADDR*)&addrSrv, nLen);
接收文件:
printf("正在接收文件......\n");
// 接收图片
if (SOCKET_ERROR != recvfrom(sockClient, szFileInfo,
sizeof(szFileInfo), 0, (SOCKADDR*)&addrClnt, &nLen))
memcpy(&stPhoto, szFileInfo,
sizeof(stPhoto));
if (0 == strncmp(stPhoto.buf,
"finish", 6))
printf("文件接收完成......\n");
int n = fwrite(stPhoto.buf, 1, stPhoto.nSize, fp2);
//printf("write %d byte\n", n);
7. 常见错误
包含&windows.h&和winsock.h后重定义问题:
[解决方案]
由以上代码可以看出如果在没有定义WIN32_LEAN_AND_MEAN宏的大前
提下windows.h有可能包含winsock.h 头文件,因此我们得出一个很简单
的解决方法就是在包含&windows.h&之前定义WIN32_LEAN_AND_MEAN宏,如
#define WIN32_LEAN_AND_MEAN
#include &windows.h&
没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!编程题 #3
&(Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩。)
注意: 总时间限制: 1000ms 内存限制: 65536kB
下面程序的输出结果是:
#include &iostream&
class Base {
Base(int n):k(n) { }
class Big {
// 在此处补充你的代码
int main() {
Big a1(5); Big a2 = a1;
cout && a1.v && "," && a1.b.k &&
cout && a2.v && "," && a2.b.k &&
所缺代码具有如下形式:
Big ________________{ }
Big ________________{ }
#include &iostream&
using namespace
class Base {
Base(int n):k(n) { }
class Big {
// 在此处补充你的代码
Big(int n):v(n), b(n) { };
Big(Big &a):v(a.v), b(a.v) { };
int main() {
Big a1(5); Big a2 = a1;
cout && a1.v && "," && a1.b.k &&
cout && a2.v && "," && a2.b.k &&
阅读(...) 评论()这个题目的噱头太大,要真的写起来, 足够写一本书了。
本人是过来人, 结合自身的体会和大家交流一下,希望新人能少走弯路。
每个人的情况不一样,我下面的描述可能并不适合每一个看到这篇文章的人。
一、C/C++语言
&&&&& 如果你的基础很差, 建议不要一开始就学C++语言,从C开始学起,对程序有个初步的认识,循序渐进。C语言的书嘛,先买一本 300 页以内的,把书中的每一个例子都通过键盘敲打进去到 Visual studio里面去,然后单步执行,逐行调试去看各个变量的值。或者自行添加一些printf语句去输出变量的值。这样当你看完一本书后, 你就有编写小程序的感觉了。
记住,千万不要偷懒,不敲进去,自以为聪明, 能看懂, 或者直接从光盘复制。偷懒的代价是会花费更多的时间学习,最后还没有学会,给自己的自信心造成巨大打击,再也不想学程序了。
&&&&& C语言看完一本书后,下来你就可以买一本C++的书看了。 C++的书也是一样, 必须300页以内的那种,不要一来就想学《C++ Primer中文版》这样的好书, 因为太厚了,怕你没有信心能够看完,即使你很有信心,花费一年的时间才看完,不值得。这种经典的厚的好书, 适合作为资料查阅,不适合挨个细节都看。
还是要提醒各位,一定要把书中的例子挨个敲打到电脑里面, 单步执行。一定不要从光盘复制, 一定要单步执行。
经过两本书的磨练, 估计你对C/C++肯定有比较深入的了解了, 下来应该可以进入实战了。
二、带界面的应用程序
&&&&& 学会了C/C++语言本身,可能还没有什么成就感,毕竟都是控制台的程序, 老是输出一串字符串, 整天面对各黑框框,成就感估计不是那么爽。要是能搞个带UI界面的程序就爽了。
&&&&& 下来就看个人的志向了, 如果走微软路线, 那你下来学MFC好了,如果要走开源路线, 那开源跨平台的界面库多得是。
通用的并且简单的就是 wxWidget 了, 官方网站为&www.wxwidgets.org/ 。你下载后看具体的例子, 把里面的例子程序敲到你的 visual studio 里面, 去调试, 看运行的结果, 你也可以试着去修改例子, 添加按钮,响应按钮事件等。
走到这一步, 恭喜你,可以照葫芦画瓢的搞个小应用程序了, 还带界面。
三、网络应用程序
&&&&& 语言搞懂了,UI程序也会了, 下来该学学网络咯, 现在那个程序不需要联网啊,懂网络对你理解很多程序非常有帮助。但是网络应用程序从哪里入手呢 ?
&&&&& 我来告诉你,从《UNIX网络编程》这本书入手吧,这本书可以教会你网络套接字的底层原理,把上面的例子好好学习,自己动手写一个回应服务器。写一个服务器端,在写一个客户端。服务器端请务必学会 select 这个简单的多路复用模型,这样你才能慢慢的深入里面 poll , epoll ,IOCP 之类的模型。
四、文件操作
&&&&& 所有的程序,基本都会用到文件的读写操作,windows系统有自己的文件操作API, 比如CreateFile, DeleteFile 等,请新手不要学windows的文件操作API, 新手请学标准C语言的文件操作函数,简单易学还跨平台。就那么几个函数,三下五除二你也就学会了, fopen, fclose, fread , fwrite, fseek, ftell 就这么几个而已。
五、深刻理解内存与指针的关系
&&&&& 作为一个C/C++程序员, 从学习程序的头一天开始,就要和内存的分配释放作斗争。你必须理解内存与指针的关系。怎么样才能理解呢, 请大家去看 《高质量C/C++编程》里面自带的几个经典例子吧。把那几个例子搞得清清楚楚, 基本能够理解其中的原理了。&
六、仔细研究apache源码
&&&&& 学程序非特别是C/C++程序,非3年之功可以出山,三年对一个C/C++程序来说是一个从量变到质变的过程,三年的项目实战经验,可以让你接触到一个完整的应用程序所需要具备的骨架。但是这个阶段你写的代码,可能充满BUG, 会宕机,运行效率很差,自己回头看看一年前写的代码,可能自己都感觉恶心, 看不下去。没有关系,这种感觉是每一个进步青年都会有的。要提高自己的代码水平, 还是要像高手学习。你可能要问,公司同事的水平一般, 水平好的人家也不愿意给我讲。没有关系,开源的代码就是你像高手学习的最佳途径,开源代码是高手留下的练功秘诀, 你看了后你会突然感觉茅塞顿开, 感觉自己的水平差人家太远了。我为何要推荐apache的源码呢?
&&&&& apache的源码是高手中的高手写的,执行效率和程序堪称一绝。里面的很多思想是所有程序都通用的,搞懂了, 很多模块你也可以直接拿来使用。apache对内存池的使用, 对线程池的使用, 对模块结构的封装,非常具有实际意义。要是你能把apache的源码吃个透彻,每一个细节都搞明白了为何人家要这么实现,我可以给你说,&恭喜你 , 你离传说中的高手已经不远了。&
七、修炼C++
&&&&& 我上面说的基本都是修炼C的, 要修炼C++, 还得再花3年功夫, 才有可能练成C++高手。C++太博大精深了,其中最复杂的莫过于泛型编程思想,不要以为能写个模板类就认为泛型编程不过如此而已。仔细看看STL源码, Boost 源码, 你就知道泛型编程有多么的博大精深了。修炼C++, 可以从用C++封装的MFC,& wxWidget入手, 看高手如何通过C++语言, 封装这样庞大的UI库,里面应用了很多的C++机制, 最典型的就是多态机制, 还有很多的设计模式应用可以研究。
八、深研设计模式
&&&&&& 设计模式是程序设计的灵魂,是通用方法,当你面对一个大型项目的时候,如何设计一个有弹性的系统,是所有系统分析员应该掌握的技能。在设计模式的研究上,要结合实际的项目进行。
http://blog.csdn.net/langeldep/article/details/6333562
Views(...) Comments()[书籍][程序设计] C...
扫描二维码,下载文件到手机
相关文档推荐
文件夹内容会因为分享者操作 或审核发生变化
当前文件信息
浏览:32447次
保存:255次
喜欢:11次
您的VIP会员已过期,是否续费?
用户应遵守著作权法,尊重著作权人合法权益,不违法上传、存储并分享他人作品。举报邮箱:
京网文[0号 京ICP证100780号您的浏览器版本过低,访问速度较慢,建议安装2345浏览器,上网更快更安全。
您的位置: &
& C/C++程序设计学习与实验系统
C/C++程序设计学习与实验系统 V2015.5
【概括介绍】学习编程的好软件。【基本介绍】 原名《Turbo C/C++ for Windows 集成实验与学习环境》,支持32位与64位的WINDOWS 7,它是从事一线教学的大学教师根据多媒体教学演示和C语言初学者的特点,量身打造的一个简单易用的C/C++程序设计教学演示、学习与实验软件(支持TC2/TC3、VC6、GCC四种编译器,单步调试功能免费,没有使用日期限制)。与软件配套的《 C/C
[展开全部↓]
重要提示:
尊敬的用户,该软件属于共享(收费)软件,请考虑后进行下载!
俗话说活到老学到老,学习是人类进步的阶段,但是现代人的工作比较忙,学习的精力和兴趣就变得越来越少了。为了解决这个问题,2345软件大全小编特精心整理了一些很好用的学习软件,大家可以在上班之余在电脑上学习一些知识,下班时可以在地铁上用手机学习一点技能,不需要死记硬背,趣味的学习可以让你更加容易学会。那么问题来了,学习软件哪家强,2345软件大全帮你忙。&推荐:&&&&&
下载地址提示:推荐使用软件,解压缩更快。
高速下载地址
其他下载地址
2345软件大全欢迎用户将网页内容和下载地址转发到博客、微博、论坛等。
所有软件已经过工作人员安装检测,如不能正常运行,请检查运行环境和硬件配置,或在评论中反馈,工作人员会及时处理。
判断软件好坏,请用户参考用户评论或者软件好评度
编辑推荐软件
热门关键词}

我要回帖

更多关于 c语言编程软件 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信