`
huobengle
  • 浏览: 858328 次
文章分类
社区版块
存档分类
最新评论

使用C/C++实现Socket聊天程序(代码+实验报告)

 
阅读更多

使用C/C++实现Socket聊天程序

Initsock.h文件

  1. //initsock.h文件
  2. #include<winsock2.h>
  3. #include<stdlib.h>
  4. #include<conio.h>
  5. #include<stdio.h>
  6. #pragmacomment(lib,"WS2_32")//链接到WS2_32.lib
  7. classCInitSock
  8. {
  9. public:
  10. CInitSock(BYTEminorVer=2,BYTEmajorVer=2)
  11. {
  12. //初始化WS2_32.dll
  13. WSADATAwsaData;
  14. WORDsockVersion=MAKEWORD(minorVer,majorVer);
  15. if(::WSAStartup(sockVersion,&wsaData)!=0)
  16. {
  17. exit(0);
  18. }
  19. }
  20. ~CInitSock()
  21. {
  22. ::WSACleanup();
  23. }
  24. };

TCP版

TCPClient.cpp文件

  1. //////////////////////////////////////////////////////////
  2. //TCPClient.cpp文件
  3. /*
  4. 《使用说明》
  5. 0.运行程序前请查看是否将initsock.h
  6. 文件引入到项目中。
  7. 1.首先修改聊天对方的IP地址
  8. 2.请首先运行服务端(TCPServer)程序,再运行客户端(TCPClient)程序:
  9. 如配置正确服务端会收到相关连接信息。
  10. 3.连接成功后,需要由服务器端首先发起会话(输入消息并确认发送),
  11. 客户端收到消息后才能输入消息并确认发送到服务器端。
  12. 并且双方每次只能发送一条消息。如想发送第二条消息,需要等待该方成功
  13. 接受到另一方的消息后才能继续输入消息。
  14. */
  15. #include"InitSock.h"
  16. #include<stdio.h>
  17. #include<iostream.h>
  18. CInitSockinitSock;//初始化Winsock库
  19. intmain()
  20. {
  21. //创建套节字
  22. SOCKETs=::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
  23. if(s==INVALID_SOCKET)
  24. {
  25. printf("Failedsocket()/n");
  26. return0;
  27. }
  28. //也可以在这里调用bind函数绑定一个本地地址
  29. //否则系统将会自动安排
  30. //填写远程地址信息
  31. sockaddr_inservAddr;
  32. servAddr.sin_family=AF_INET;
  33. servAddr.sin_port=htons(4567);
  34. //注意,这里要填写服务器程序(TCPServer程序)所在机器的IP地址
  35. //如果你的计算机没有联网,直接使用127.0.0.1即可
  36. servAddr.sin_addr.S_un.S_addr=inet_addr("192.168.1.129");
  37. if(::connect(s,(sockaddr*)&servAddr,sizeof(servAddr))==-1)
  38. {
  39. printf("Failedconnect()/n");
  40. return0;
  41. }
  42. charbuff[256];
  43. charszText[256];
  44. while(TRUE)
  45. {
  46. //从服务器端接收数据
  47. intnRecv=::recv(s,buff,256,0);
  48. if(nRecv>0)
  49. {
  50. buff[nRecv]='/0';
  51. printf("接收到数据:%s/n",buff);
  52. }
  53. //向服务器端发送数据
  54. cin>>szText;
  55. szText[255]='/0';
  56. ::send(s,szText,strlen(szText),0);
  57. }
  58. //关闭套节字
  59. ::closesocket(s);
  60. return0;
  61. }

TCPServer.cpp文件

  1. //TCPServer.cpp文件
  2. /*
  3. 《使用说明》
  4. 0.运行程序前请查看是否将initsock.h
  5. 文件引入到项目中。
  6. 1.首先修改聊天对方的IP地址
  7. 2.请首先运行服务端(TCPServer)程序,再运行客户端(TCPClient)程序:
  8. 如配置正确服务端会收到相关连接信息。
  9. 3.连接成功后,需要由服务器端首先发起会话(输入消息并确认发送),
  10. 客户端收到消息后才能输入消息并确认发送到服务器端。
  11. 并且双方每次只能发送一条消息。如想发送第二条消息,需要等待该方成功
  12. 接受到另一方的消息后才能继续输入消息。
  13. */
  14. #include"InitSock.h"
  15. #include<stdio.h>
  16. #include<iostream.h>
  17. CInitSockinitSock;//初始化Winsock库
  18. intmain()
  19. {
  20. //创建套节字
  21. SOCKETsListen=::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
  22. if(sListen==INVALID_SOCKET)
  23. {
  24. printf("Failedsocket()/n");
  25. return0;
  26. }
  27. //填充sockaddr_in结构
  28. sockaddr_insin;
  29. sin.sin_family=AF_INET;
  30. sin.sin_port=htons(4567);
  31. sin.sin_addr.S_un.S_addr=INADDR_ANY;
  32. //绑定这个套节字到一个本地地址
  33. if(::bind(sListen,(LPSOCKADDR)&sin,sizeof(sin))==SOCKET_ERROR)
  34. {
  35. printf("Failedbind()/n");
  36. return0;
  37. }
  38. //进入监听模式
  39. if(::listen(sListen,2)==SOCKET_ERROR)
  40. {
  41. printf("Failedlisten()/n");
  42. return0;
  43. }
  44. //循环接受客户的连接请求
  45. sockaddr_inremoteAddr;
  46. intnAddrLen=sizeof(remoteAddr);
  47. SOCKETsClient=0;
  48. charszText[]="TCPServerDemo!/r/n";
  49. while(sClient==0)
  50. {
  51. //接受一个新连接
  52. sClient=::accept(sListen,(SOCKADDR*)&remoteAddr,&nAddrLen);
  53. if(sClient==INVALID_SOCKET)
  54. {
  55. printf("Failedaccept()");
  56. }
  57. printf("接受到一个连接:%s/r/n",inet_ntoa(remoteAddr.sin_addr));
  58. continue;
  59. }
  60. while(TRUE)
  61. {
  62. //向客户端发送数据
  63. gets(szText);
  64. ::send(sClient,szText,strlen(szText),0);
  65. //从客户端接收数据
  66. charbuff[256];
  67. intnRecv=::recv(sClient,buff,256,0);
  68. if(nRecv>0)
  69. {
  70. buff[nRecv]='/0';
  71. printf("接收到数据:%s/n",buff);
  72. }
  73. }
  74. //关闭同客户端的连接
  75. ::closesocket(sClient);
  76. //关闭监听套节字
  77. ::closesocket(sListen);
  78. return0;
  79. }

UDP版

  1. //Chat.cpp:Definestheentrypointfortheconsoleapplication.
  2. //
  3. /*
  4. 《使用说明》
  5. 0.运行程序前请查看是否将initsock.h
  6. 文件引入到项目中。
  7. 1.首先修改聊天对方的IP地址
  8. 2.运行程序:如配置正确另一方会收到相关连接信息。
  9. 3.输入消息:在每次输入完欲发送的消息后,需要连续敲击两次回车。
  10. 4.本程序有诸多缺陷:对用户输入的消息不能即时回显到控制台,
  11. 需要在敲击两次回车后回显到屏幕。
  12. */
  13. #include"stdafx.h"
  14. #include<iostream>
  15. #include<stdlib.h>
  16. #include<STDIO.H>
  17. #include<windows.h>
  18. #include"InitSock.h"
  19. usingnamespacestd;
  20. CInitSockinitSock;//初始化Winsock库
  21. DWORDreceiverMark;//接收消息者线程标识符
  22. DWORDsenderMark;//发送者线程标识符
  23. /**
  24. *定义信号量
  25. */
  26. DWORDWINAPIReceiver(LPVOID);
  27. DWORDWINAPISender(LPVOID);
  28. //接收数据
  29. charbuff[1024];
  30. sockaddr_inaddr;
  31. intnLen=sizeof(addr);
  32. SOCKETs;
  33. intmain(intargc,char*argv[])
  34. {
  35. //创建套节字
  36. s=::socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
  37. //u_longiMode=1;
  38. //ioctlsocket(s,FIONBIO,&iMode);
  39. if(s==INVALID_SOCKET)
  40. {
  41. printf("Failedsocket()/n");
  42. return0;
  43. }
  44. //填充sockaddr_in结构
  45. sockaddr_insin;
  46. sin.sin_family=AF_INET;
  47. sin.sin_port=htons(4567);
  48. sin.sin_addr.S_un.S_addr=INADDR_ANY;
  49. addr.sin_family=AF_INET;
  50. addr.sin_port=htons(4567);
  51. //注意,这里要填写服务器程序所在机器的IP地址
  52. //如果你的计算机没有联网,直接使用127.0.0.1即可
  53. addr.sin_addr.S_un.S_addr=inet_addr("192.168.1.129");
  54. //绑定这个套节字到一个本地地址
  55. if(::bind(s,(LPSOCKADDR)&sin,sizeof(sin))==SOCKET_ERROR)
  56. {
  57. printf("Failedbind()/n");
  58. return0;
  59. }
  60. //发送数据
  61. charszText[]="PC请求连接.../r/n";
  62. ::sendto(s,szText,strlen(szText),0,(sockaddr*)&addr,sizeof(addr));
  63. CreateThread(NULL,0,Receiver,NULL,0,&receiverMark);
  64. CreateThread(NULL,0,Sender,NULL,0,&senderMark);
  65. boolisContinue=true;
  66. while(isContinue)
  67. {
  68. if(getche()==96){//按~后终止程序运行
  69. isContinue=false;
  70. }
  71. }
  72. system("PAUSE");
  73. return0;
  74. }
  75. /**
  76. *接收者
  77. */
  78. DWORDWINAPIReceiver(LPVOIDlpParam)
  79. {
  80. while(1)
  81. {
  82. intnRecv=::recvfrom(s,buff,1024,0,(sockaddr*)&addr,&nLen);
  83. if(nRecv>0)
  84. {
  85. buff[nRecv]='/0';
  86. printf("Receiveddata(%s):%s/n",::inet_ntoa(addr.sin_addr),buff);
  87. }
  88. }
  89. return0;
  90. }
  91. /**
  92. *发送者
  93. */
  94. DWORDWINAPISender(LPVOIDlpPara)
  95. {
  96. while(1)
  97. {
  98. cout<<"Inputyourmessage:";
  99. //发送数据
  100. chartext[256];
  101. cin>>text;
  102. text[255]='/0';
  103. cout<<text<<endl;
  104. ::sendto(s,text,strlen(text),0,(sockaddr*)&addr,sizeof(addr));
  105. }
  106. return0;
  107. }

鉴于很多同学说拷贝的代码无法运行,

特此将源代码和实验报告上传于此:下载

解压密码:yexianyi20081216

北航软件学院《一级实践》实验报告<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

学号:GS0821594   姓名:叶现一               第 13 周

内容

训练

使用C/C++实现Socket聊天程序

解决该问题的思路

解决该问题的整体方案不外有二:

1)基于TCPSocket连接;(2)基于UDPSocket连接;

但是,针对每种方案又各有很多具体的实现方法。

在本次实验中,我先后开发了基于TCP连接和UDP连接的Socket聊天程序。具体实现思路如下:

(一) 基于TCP连接Socket聊天程序

基于该连接的聊天程序需要至少具备一个服务器端(Server)和一个客户端(Client)。在本程序中,一个用户作为Server端,另一个用户作为Client端。也就是说,作为Server端的用户,需要首先启动程序,等待Client端的连接请求。当TCP连接握手以后,双方方可进行交互。(注:在本程序中Server端并不是单独存在。它也可以向他的Client端发送消息。)但是本程序实现的交互功能十分简单,具有很多限制。当Client端与Server端握手以后,Server端需要首先发起会话;Client端在收到消息后再回复一条消息给Server端;同样,Server端在收到消息后再回复一条消息给Client端……以此类推。并且,无论是Server端还是Client端每次发送消息只能发送一条。

造成交互操作具有诸多限制的主要原因是,我在Server端和Client端使用了一个While循环,它们的伪代码分别如下:

Client

Server

while(TRUE)

{

Server端接收消息

{

}

Server端发送消息

{

}

}

while(TRUE)

{

Client端发送消息

{

}

Client端接收消息

{

}

}

(二) 基于UDP连接Socket聊天程序

基于该连接的聊天程序不需要具备服务器端(Server),每个客户端(Client)既是服务器端也是客户端。也就是说每个Client端自身既可以自行接收其它用户发来的消息,也可以向其它Client端发送消息,不需要事先与其他用户进行握手连接。

由于在默认情况下WinSock接口的recvfrom()sendto()都会在被调用时阻塞当前线程,也就是说如果程序正在接受其他用户发来的数据,那么它就不能够执行发送数据的任务,反之相同。所以为解决该问题一般有以下几种解决方案:采用Select模型、WSAAsyncSelect模型、WSAEventSelect模型、重叠(Overlapped)模型和完成接口(Completion port)模型。在本程序中,由于我没能在短时间内学会上述方案中的任一种,因此采用了多线程技术去实现消息接收和发送的同步问题。也就是说,在程序中创建两个线程,一个线程负责发送消息,另一个消息负责接受消息。两个线程交替运行,从而达到同时收发消息的目的。当然采用多线程方式解决消息收发同步问题可以移除上个程序中每个用户一次只能发送一条消息的限制。

本周开发源代码

代码的功能简述

使用C/C++实现Socket聊天程序:

TCP版:服务器端用户和客户端用户在成功连接后,其中一方通过控制台输入消息,依次轮流向另一方发送数据。要求,服务器端首先发起会话,并且双方每次只能发送一条消息。

UDP版:任一端用户通过指定IP地址将消息发送到另一端的用户。交互双方通过控制台输入消息向另一方发送数据。没有任何发送限制。

开发的收获

理解了TCP连接和UDP连接的基本原理和工作过程。

复习了关于Windows多线程及进程同步的相关知识。

开发中碰到的主要困难

对于TCP版:

在考虑如何解决消息的收发同步问题上遇到了困难。最终使用了不佳方案:通过在服务器端和客户端分别运行while循环并依次进行数据收发工作的方式解决数据收发同步问题。

对于UDP版:

同样在考虑如何解决消息的收发同步问题上遇到了困难。但这次使用了多线程解决该问题。

开发中未能解决的问题

对于UDP版:

为何第一次消息输入完毕敲击一次回车后,只有消息的第一个字符没能发送出去,而其它字符却可以被成功发送出去?而且当第二次输入消息敲回车后消息就能被全部发送出去?

为何消息输入完毕后需要按两次回车键才能将消息发送到另一端?

为什么输入的消息不能即时回显到发送者屏幕上?只有当敲击二次回车后用户输入的欲发送消息才会显现出来?

如何才能避免用户在输入消息的同时也能正常接收消息?也就是不至于打断用户已输入的消息的前提下,显示接收到的消息。

针对本周训练内容自己设计的案例

案例的主要功能

同代码的功能简述

用到的基本知识

相关Winsock编程接口;TCP连接和UDP连接基本工作原理;Windows多线程;

进程同步

程序注意了哪些规范

代码格式、常量的定义、函数的声明

你进行了哪些测试

程序进行了哪些有效性检查

你是如何保证程序的高效率的

注意:实验报告和案例源代码须在本次小组讨论会前提交

分享到:
评论

相关推荐

    使用C/C++实现Socket聊天程序

    使用C/C++实现Socket聊天程序,本程序采用C++编写。具有良好的重用性。为初学者提供了一个很好的范例

    C/C++实现Socket聊天程序

    用C/C++实现Socket聊天程序 包括客户端和服务端

    使用C_C++实现Socket聊天程序

    使用C_C++实现Socket聊天程序 聊天程序源代码在一个册子里面 方便好用 详细

    C++实现自助点餐系统源码+实验报告+文档说明(95分以上大作业项目).zip

    C++实现自助点餐系统源码+实验报告+文档说明(95分以上大作业项目).zip 该项目是个人大作业项目源码,评审分达到95分以上,都经过严格调试,确保可以运行!放心下载使用。 C++实现自助点餐系统源码+实验报告+文档...

    操作系统文件复制实验C++源码(含代码注释+实验报告).zip

    操作系统文件复制实验C++源码(含代码注释+实验报告).zip操作系统文件复制实验C++源码(含代码注释+实验报告).zip操作系统文件复制实验C++源码(含代码注释+实验报告).zip操作系统文件复制实验C++源码(含代码注释+实验...

    c++学生成绩管理系统源代码+实验报告

    c++学生成绩管理系统源代码+实验报告, 文件读写、班级创建、添加学生、修改学生信息、等等

    用C/C++实现代码的动态修改(SMC)

    由于该技术需要直接读写对内存中的机器码,所以多采用汇编语言实现,这使得很多想在自己的程序中使用SMC技术进行软件加密的C/C++程序员望而却步。针对这种现状,本文提出了几种基于C/C++语言的机器指令定位方法,...

    c/c++ 聊天程序

    聊天程序 c/C++ 经典中的经典程序代码 聊天程序 c/C++ 经典中的经典程序代码 聊天程序 c/C++ 经典中的经典程序代码

    数据结构课设基于C++的交通咨询系统源码+实验报告+代码注释.zip

    数据结构课设基于C++的交通咨询系统源码+实验报告+代码注释.zip数据结构课设基于C++的交通咨询系统源码+实验报告+代码注释.zip数据结构课设基于C++的交通咨询系统源码+实验报告+代码注释.zip 该项目是个人课设项目,...

    数据结构课设基于C++的图书管理系统源码+实验报告+代码注释.zip

    数据结构课设基于C++的图书管理系统源码+实验报告+代码注释.zip 该项目是个人毕设项目,答辩评审分达到95分,代码都经过调试测试,确保可以运行!欢迎下载使用,可用于小白学习、进阶。 该资源主要针对计算机、通信...

    C/C++实现聊天室(简洁版)

    1.源代码未经任何封装,逻辑清晰,简洁明了 2.使用MFC进行界面编程 3.服务器端有windows版和LInux版 4.压缩包中已存在我编译好的软件,可直接使用 5.项目由VS2022建立,如果使用低版本的VS请自行设置一些选项 6.代码...

    操作系统实验一报告【使用C语言/C++实现时间片轮转调度算法】

    操作系统实验一报告【使用C语言/C++实现时间片轮转调度算法】

    基于C语言/C++基础的跨年烟花代码

    C语言/C++基础之跨年烟花代码,适合初学C语言/C++的小伙伴学习研究,博客中有对应的讲解和演示,避免走弯路,费时费力。也真心希望能够帮助正在苦学C语言/C++ 程序设计的小伙伴们,你们的成长是我最大的幸福

    C++编写的Socket聊天程序源代码

    C++编写的Socket聊天程序源代码,程序所在文件夹名:TCP聊天服务器端 ;TCP聊天客户端

    c++基于socket聊天程序

    c++基于socket聊天程序 简单 方便

    C语言/C++基础之跨年烟花代码

    C语言/C++基础之跨年烟花代码,适合初学C语言/C++的小伙伴学习研究,博客中有对应的讲解和演示,避免走弯路,费时费力。也真心希望能够帮助正在苦学C语言/C++ 程序设计的小伙伴们,你们的成长是我最大的幸福

    c/c++ 猜数字游戏 程序代码

    c/c++ 猜数字 游戏 程序代码 c/c++ 猜数字 程序代码 ,通过这个代码程序,你可以输入四个数字,通过一定的猜测,得出正确的数字序列。代码中还有特权模式。你输入密码后,可以得到更准确的提示!!做报告之代码救急...

    使用c/c++实现语义分析器

    但由于之前我设计文法大多只是为了测试使用,所以文法很不规范,这直接导致了语义子程序十分难实现,所以要想实现一个好的语义分析器,必须先设计好你的文法。 需要注意的是,这个语义分析器是建立在我之前写的语法...

Global site tag (gtag.js) - Google Analytics