TCP/IP协议(面向连接协议)类似于打电话时,对方一定在手机附近并且此刻都在和对方进行通话。一定保证双方都在线,才能进行数据传输。UDP/IP协议(无连接协议)就像邮箱,不保证对方一定在等你邮件且对方不在你也可以给对方发送数据。实际上TCP协议、UDP协议,还有重要的TCP协议中的三次握手(建立连接)和四次挥手(关闭连接)等在网上也都解释得非常详细了,所以我就不多说了。

  Server端程序代码:

  1. /*
  2. * 服务器端 Server.c
  3. *
  4. */
  5. #include <winsock2.h>
  6. #include <stdio.h>
  7. #include <string.h>
  8.  
  9. #define BUFFSIZE 1024
  10.  
  11. int main(int argc, char**argv)
  12. {
  13. int Ret;
  14. WSADATA wsaData;
  15. SOCKET ListeningSocket;
  16. SOCKET NewConnection;
  17. SOCKADDR_IN ServerAddr;
  18. SOCKADDR_IN ClientAddr;
  19. int ClientAddrLen = sizeof(ClientAddr);
  20. unsigned short Port = 5150;
  21. char sendData[BUFFSIZE];
  22. char recvData[BUFFSIZE];
  23.  
  24. if((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)
  25. {
  26. printf("WSASTARTUP_ERROR: %d\n", Ret);
  27. return 0;
  28. }
  29.  
  30. //创建一个套接字来监听客户机连接
  31. if((ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
  32. {
  33. printf("SOCKET_ERROR: %d\n", INVALID_SOCKET);
  34. return 0;
  35. }
  36.  
  37. /*
  38. * 填充SOCKADDR_IN结构,这个结构将告知bind我们想要在5150端口监听所有接口上的连接
  39. */
  40. ServerAddr.sin_family = AF_INET;
  41. ServerAddr.sin_port = htons(Port); //将端口变量从主机字节顺序转换位网络字节顺序
  42. ServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
  43.  
  44. //使用bind将这个地址信息和套接字绑定起来
  45. if(bind(ListeningSocket, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR)
  46. {
  47. printf("BIND_ERROR: %d\n", SOCKET_ERROR);
  48. return 0;
  49. }
  50.  
  51. //监听客户机连接。这里使用5个backlog
  52. if(listen(ListeningSocket, 5) == SOCKET_ERROR)
  53. {
  54. printf("LISTEN_ERROR: %d\n", SOCKET_ERROR);
  55. return 0;
  56. }
  57.  
  58. //连接到达时,接受连接
  59. printf("正在接受连接...");
  60. if((NewConnection = accept(ListeningSocket, (SOCKADDR *)&ClientAddr, &ClientAddrLen)) == INVALID_SOCKET)
  61. {
  62. printf("ACCPET_ERROR: %d\n", INVALID_SOCKET);
  63. closesocket(ListeningSocket);
  64. return 0;
  65. }
  66. printf("检测到一个连接: %s 端口:%d\n", inet_ntoa(ClientAddr.sin_addr), ntohs(ClientAddr.sin_port));
  67.  
  68. //聊天
  69. while(true)
  70. {
  71. //接收数据
  72. Ret = recv(NewConnection, recvData, BUFFSIZE, 0);
  73. if(Ret > 0)
  74. printf("C.C.: %s\n", recvData);
  75. else if(Ret < 0)
  76. printf("RECV_ERROR: %d\n", SOCKET_ERROR);
  77. else
  78. {
  79. printf("对方退出程序,聊天结束!");
  80. break;
  81. }
  82.  
  83. //发送数据
  84. printf("\n鲁鲁:");
  85. scanf("%s", sendData);
  86. if(strcmp(sendData, "quit") == 0) //退出
  87. break;
  88. if(send(NewConnection, sendData, BUFFSIZE, 0) == SOCKET_ERROR)
  89. {
  90. printf("消息发送失败!\n");
  91. break;
  92. }
  93. }
  94. //从容关闭
  95. shutdown(NewConnection, SD_BOTH);
  96.  
  97. //完成新接受的连接后,用closesocket API关闭这些套接字
  98. closesocket(NewConnection);
  99. closesocket(ListeningSocket);
  100.  
  101. //应用程序完成对接的处理后,调用WSACleanup
  102. if(WSACleanup() == SOCKET_ERROR)
  103. {
  104. printf("WSACLEANUP_ERROR: %d\n", WSAGetLastError());
  105. return 0;
  106. }
  107.  
  108. system("pause");
  109. return 0;
  110. }

  Client端程序代码:

  1. /*
  2. * 客户端 Client.c
  3. *
  4. */
  5. #include <winsock2.h>
  6. #include <stdio.h>
  7. #include <string.h>
  8.  
  9. #define BUFFSIZE 1024
  10.  
  11. int main(int argc, char**argv)
  12. {
  13. int Ret;
  14. WSADATA wsaData;
  15. SOCKET s;
  16. SOCKADDR_IN ServerAddr;
  17. unsigned short Port = 5150;
  18. char sendData[BUFFSIZE];
  19. char recvData[BUFFSIZE];
  20.  
  21. if((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)
  22. {
  23. printf("WSASTARTUP_ERROR: %d\n", Ret);
  24. return 0;
  25. }
  26.  
  27. if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
  28. {
  29. printf("SOCKET_ERROR: %d\n", INVALID_SOCKET);
  30. return 0;
  31. }
  32.  
  33. ServerAddr.sin_family = AF_INET;
  34. ServerAddr.sin_port = htons(Port);
  35. ServerAddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.101");// 这里S_un.S_addr在不同的IDE中可能不一样,然后IPv4地址使用该程序所运行在的PC上的IPv4地址
  36.  
  37. if((connect(s, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr))) == SOCKET_ERROR)
  38. {
  39. printf("CONNECT_ERROR: %d\n", SOCKET_ERROR);
  40. closesocket(s);
  41. return 0;
  42. }
  43.  
  44. //Chat
  45. while(true)
  46. {
  47. printf("\nC.C:");
  48. scanf("%s", sendData);
  49. if(strcmp(sendData, "quit") == 0) //quit
  50. break;
  51. if(send(s, sendData, BUFFSIZE, 0) == SOCKET_ERROR)
  52. {
  53. printf("消息发送失败!\n");
  54. break;
  55. }
  56.  
  57. Ret = recv(s, recvData, BUFFSIZE, 0);
  58. if(Ret > 0)
  59. printf("鲁鲁: %s\n", recvData);
  60. else if(Ret < 0)
  61. printf("RECV_ERROR: %d\n", SOCKET_ERROR);
  62. else
  63. {
  64. printf("对方退出程序,聊天结束!");
  65. break;
  66. }
  67. }
  68. shutdown(s, SD_BOTH);
  69. closesocket(s);
  70.  
  71. if(WSACleanup() == SOCKET_ERROR)
  72. {
  73. printf("WSACLEANUP_ERROR: %d\n", WSAGetLastError());
  74. return 0;
  75. }
  76.  
  77. system("pause");
  78. return 0;
  79. }

  运行结果:

  对于所有可能出现的错误我都加上了会出错的函数名前缀,以便于定位出现错误的位置。

  其他的书上解释得很详细,就不暴露自己水平了233...

p.s.2018-05-13 15:10:46

  AF_INET的原型是:

  1. #define AF_INET 2

  然后关于客户端代码中的inet_addr()可看一下我的这篇,其中有一段相关解释。

  

windows网络编程-C语言实现简单的TCP协议聊天的更多相关文章

  1. windows网络编程-C语言实现简单的UDP协议聊天

    与TCP协议下编写服务端程序代码类似,但因为是无连接的形式,所以不需要监听. 这次,我用了一点不同的想法:我建立一个服务端,用了两个端口和两个套接字,把服务端作为一个数据转发的中转站,使得客户机之间进 ...

  2. linux 网络编程:客户端与服务器通过TCP协议相互通信 + UDP

    1.TCP编程的客户端一般步骤: 1.创建一个socket,用函数socket(): 2.设置socket属性,用函数setsockopt():* 可选: 3.绑定IP地址.端口等信息到socket上 ...

  3. {网络编程}和{多线程}应用:基于TCP协议【实现多个客户端发送文件给一个服务器端】--练习

    要求: 实现多个客户端发送文件给一个服务器端 提示:多个人创建客户端发送文件,服务端循环接收socket,从socket中获取文件 说明:这里我们只要建立一个服务端就可以了,然后让多台电脑使用客户端给 ...

  4. [转]Windows网络编程学习-面向连接的编程方式

    直接附上原文链接:windows 网络编程学习-面向连接的编程方式

  5. Windows网络编程 2 【转】

    Windows网络编程使用winsock.Winsock是一个基于Socket模型的API,在Windows系统中广泛使用.使用Winsock进行网络编程需要包含头文件Winsock2.h,需要使用库 ...

  6. 【Hadoop离线基础总结】zookeeper的介绍以及集群环境搭建、网络编程和RPC的简单了解

    ZooKeeper的介绍以及集群环境搭建.网络编程和RPC的简单了解 ZooKeeper介绍 概述 ZooKeeper是一个分布式协调服务的开源框架,主要用来解决分布式集群中应用系统的一致性问题.例如 ...

  7. Android网络编程要学的东西与Http协议学习

    本节引言: 本节开始我们来学习Android网络编程相关的一些东西:Android端网络编程是要干嘛?http协议的学习,使用自带扣脚Json解析类解析Json,XML解析常用的几种方式,HttpUr ...

  8. Python网络编程03 /缓存区、基于TCP的socket循环通信、执行远程命令、socketserver通信

    Python网络编程03 /缓存区.基于TCP的socket循环通信.执行远程命令.socketserver通信 目录 Python网络编程03 /缓存区.基于TCP的socket循环通信.执行远程命 ...

  9. 网游中的网络编程系列1:UDP vs. TCP

    原文:UDP vs. TCP,作者是Glenn Fiedler,专注于游戏网络编程相关工作多年. 目录 网游中的网络编程系列1:UDP vs. TCP 网游中的网络编程2:发送和接收数据包 网游中的网 ...

随机推荐

  1. 老生常谈--Java值传递和引用传递

    起因 前两天面试被问到了这个问题,虽然之前老早就了解过这个问题,但是并没有深入了解,所以面试的时候一下子慌了,菜是原罪,今天菜鸡来补补基础知识. 其实这个问题一直是被讨论的,常见的三种说法就是,1,J ...

  2. C# 程序集(Assembly)

    程序集 程序集是代码进行编译是的一个逻辑单元,把相关的代码和类型进行组合,然后生成PE文件.程序集只是逻辑上的划分,一个程序集可以只由一个文件组成,也可由多个文件组成.不管是单文件程序集还是多文件程序 ...

  3. Nuxt的路由动画效果

    Nuxt.js提供两种方法为路由提供动画效果,一种是全局的,一种是针对单独页面的 全局动画默认使用page来进行设置,例如现在我们为每个页面都设置一个进入和退出时的渐隐渐现的效果.我们可以先在根目录的 ...

  4. input的number类型只能输入正数,禁止负数输入

    <input type="number" max="10" min='1' id='number'> <script> document ...

  5. ssh复制秘钥成功后仍然需要输入密码

    执行免秘钥操作 ssh-copy-id -i ~/.ssh/id_rsa.pub lyg@192.168.1.65 被登录机器的文件权限: //用户权限 chmod 700 /home/usernam ...

  6. bit Buffer

    在音频流解析过程中,常常会涉及到顺序读取某些bit的操作. #include<stdio.h> typedef struct _BIT_BUF { unsigned char buffer ...

  7. Requests库网络爬虫实战

    实例一:页面的爬取 >>> import requests>>> r= requests.get("https://item.jd.com/1000037 ...

  8. 吴裕雄 python 机器学习——数据预处理包裹式特征选取模型

    from sklearn.svm import LinearSVC from sklearn.datasets import load_iris from sklearn.feature_select ...

  9. 4500-X验证镜像完整性

    1.配置IP地址: Switch(config)#int f1Switch(config-if)#ip add 10.1.1.1 255.255.255.0Switch(config-if)#no s ...

  10. 重新梳理IT知识之java-05面向对象(一)

    一.Java面向对象学习的三条主线: 1.Java类及类的成员:属性.方法.构造器:代码块.内部类 2.面向对象的三大特征:封装性.继承性.多态性.(抽象性) 3.其他关键字:this.super.s ...