基于TCP的服务器端/客户端的C语言代码实现和工作原理
网络协议系列1介绍了:基于网络协议的套接字一般分为TCP套接字和UDP套接字,TCP套接字是面向对象(steam)
- 数据通信中协议栈分为7层,对于程序员而言,掌握4层协议栈就足够了。
下面将重点介绍这4层的主要作用:
链路层:是物理链接领域标准化的结果,专门定义LAN,WAN,MAN等网络标准。
IP层:物理连接成功,就要传输数据了。IP层就是考虑向目标传输数据需要经过哪些路径。如果数据传输中发生路径错误,则选择其他路径;但IP层无法应对数据传输错误的问题
TCP/UDP层:IP层只关注1个数据包(数据传输的基本单元)的传输,但无法保证数传输的准确性及重传;TCP/UDP层存在于IP层上,决定主机之间数据传输的方式,并具有重传的功能。
TCP服务端函数调用顺序
TCP客户端函数调用顺序
实现迭代服务器端和客户端
回声(echo)服务器端和客户端,就是服务器端将客户端传给的数据原封不动的传给客户端。
- 服务端的代码:
#include<stdio.h>
#include<stdlib.h>
#include<winsock2.h>void ErrorHandling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}/* 创建服务端的套接字 */
int main(int argc, char *argv[])
{WSADATA wsaData;SOCKET hServSock, hClntSock;SOCKADDR_IN servAddr, clntAddr;int szClntAddr;int strlen = 0;char message[1024];if (argc != 2){printf("Usage: %s <port>\n", argv[0]);exit(1);}/* 设置程序中用到的Winsock版本,并初始化相应版本的库,成功时返回0。 */// wVersionRequested: 用到Winsock的版本信息;WORD是通过typedef定义的 //unsigned short类型,若Winsock版本为1.2(1主版本号,2副版本号),// 应该传递0x0201。借助MAKEWORD宏定义构造高8位为副版本号,低8位为主版//本号的WORD型版本信息。lpWSAData:表示wsaData结构体变量的地址,通过//WSAStartup函数给相关变量赋初值if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { ErrorHandling("WSAStartup() error!"); }//创建套接字,成功时返回套接字句柄,失败时返回INVALID_SOCKET。hServSock = socket(PF_INET, SOCK_STREAM, 0); if (hServSock == INVALID_SOCKET){ErrorHandling("socket() error");}memset(&servAddr, 0, sizeof(servAddr));servAddr.sin_family = AF_INET;servAddr.sin_addr.s_addr = htonl(INADDR_ANY);servAddr.sin_port = htons(atoi(argv[1]));/* 给套接字分配ip和port,成功时返回0,失败时返回SOCKET_ERROR */if (bind(hServSock, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR){ErrorHandling("bind() error");}if (listen(hServSock, 5) == SOCKET_ERROR)//成功时返回0,失败时返回SOCKET_ERROR{ErrorHandling("listen() error");}szClntAddr = sizeof(clntAddr);for (int i = 0; i < 5; i++){/* 受理客户端的连接请求,成功时返回套接字的句柄,失败时返回INVALID_SOCKET */hClntSock = accept(hServSock, (SOCKADDR*)&clntAddr, &szClntAddr);if (hClntSock == INVALID_SOCKET){ErrorHandling("accept() error");}else{printf("connect client: %d \n", i+1);}while ((strlen = recv(hClntSock, message, 1024, 0)) != 0) //不停的接收客户端发来的数据{send(hClntSock, message, strlen, 0);//向客户端发送,客户端发的数据}closesocket(hClntSock);}closesocket(hServSock);WSACleanup();return 0;//system("pause");
}
- 客户端的代码:
#include <stdio.h>
#include<stdlib.h>
#include<winsock2.h>
void ErrorHandling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}
int main(int argc, char *argv[])
{WSADATA wsaData;SOCKET hSocket;SOCKADDR_IN servAddr;char message[1024];int strLen;if (argc != 3){printf("Usage : %s <IP> <port>\n", argv[0]);exit(1);}/* 设置程序中用到的Winsock版本,并初始化相应版本的库,成功时返回0。 */// wVersionRequested: 用到Winsock的版本信息;WORD是通过typedef定义的 //unsigned short类型,若Winsock版本为1.2(1主版本号,2副版本号),// 应该传递0x0201。借助MAKEWORD宏定义构造高8位为副版本号,低8位为主版//本号的WORD型版本信息。lpWSAData:表示wsaData结构体变量的地址,通过//WSAStartup函数给相关变量赋初值if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { ErrorHandling("WSAStartup() error!"); }//成功时返回套接字句柄,失败时返回INVALID_SOCKET。hSocket = socket(PF_INET, SOCK_STREAM, 0); if (hSocket == INVALID_SOCKET){ErrorHandling("socket() error");}memset(&servAddr, 0, sizeof(servAddr));servAddr.sin_family = AF_INET;//servAddr.sin_addr.s_addr = inet_addr(argv[1]);//servAddr.sin_port = htons(atoi(argv[2]));servAddr.sin_addr.s_addr = inet_addr("127.0.0.1");servAddr.sin_port = htons(atoi("9190"));/* 向服务器端发出连接请求,成功时返回0,失败时返回SOCKET_ERROR */if (connect(hSocket, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR){ErrorHandling("connect() error!");GetLastError();}while (1){//fputs("Input message(Q to quit): ", stdout);fgets(message, 1024, stdin);//接收cmd控制台输入的数据if ((!strcmp(message, "q\n")) || (!strcmp(message, "Q\n"))) //当输入q或Q时,才向服务器发送数据break;send(hSocket, message, strlen(message), 0); //将接收到的数据发送给服务端strLen = recv(hSocket, message, strlen(message)-1, 0);//接收服务器端发送过来的数据message[strLen] = 0;printf("Message from serve: %s", message);}closesocket(hSocket); //关闭套接字函数//winsock相关的库都归还给windows操作系统,无法在调用winsock相关的函数,注销winsock库WSACleanup();system("pause");return 0;
}
- 客户端传给服务端的数据,在客户端处展现出来(回显)
– step1:先运行服务客户端的代码。
step2:运行客户端,客户端传服务端啥,服务端返回客户端啥(实现回显功能)
本代码的bug:当出现过一次客户端没传给服务端成功时,则后面客户端每次传给服务端的,都是上一次的数据,而不是当前数据。(具体原因,我目前也没想明白)
TCP通信原理
-TCP套接字的IO缓冲
基于TCP的服务器端/客户端的C语言代码实现和工作原理相关推荐
- 四 基于TCP的服务器端/客户端
** 第四章 基于TCP的服务器端/客户端(1) ** 主要内容: 这里我们讨论通过套接字收发数据 1.TCP与UDP的区别数据传输方式不同 2.协议栈的层次关系:链路层->IP层->tc ...
- 创建收发文件的服务器端 客户端,TCP/IP网络编程 Chap.5 基于TCP的服务器端/客户端(2)...
已知字符串长度情况下完善回声客户端 # gcc echo_client2.c -o eclient2 # ./eclient2 127.0.0.1 9190 Connected Input messa ...
- Part 1 start network programming:chapter SIX: 基于UDP的服务器端/客户端
第六章:基于UDP的服务器端/客户端 上面的第四章和第五章学习了TCP相关的东西.东西比较多,这里学习一下UDP. 6.1 理解IDP 在TCP/ IP协议栈中(在前面的文章中),上面第二层传输层分为 ...
- TCP/IP网络编程_第6章基于UDP的服务器端/客户端
6.1 理解 DUP 我们在第4章学习TCP的过程中, 还同时了解了 TCP/IP 协议. 在4层TCP/IP模型中, 上数第二层传输(Transport)层分为TCP和UDP这两种. 数据交换过程可 ...
- Linux网络编程 - 基于UDP的服务器端/客户端
一 理解UDP 1.0 UDP协议简介 UDP(User Datagram Protocol,用户数据报协议) [RFC 768] UDP协议的数据传输单元叫 UDP用户数据报,而TCP协议的数据传输 ...
- 基于UDP的服务器端/客户端
理解UDP UDP套接字的特点 下面通过信件说明UDP的工作原理.寄信前先在信封上填好寄信人和收信人的地址,之后贴上邮票放进邮筒即可. 无法确认对方是否收到信件,并且在邮寄过程中可能发生信件丢失的情况 ...
- c52传感器温度显示c语言编程,基于STC89C52的数字温度计 附C语言代码.doc
基于STC89C52的数字温度计 附C语言代码 <数字显示温度计>论文 学校: 华侨大学 学院: 信息科学与工程学院 班级:10级 集成电路设计与集成系统 组别: 自控06组 组员:*** ...
- 【学习笔记】在windows下进行基于TCP的本地客户端和服务端socket通信
文章目录 socket介绍 java中使用socket 基于tcp的socket通信 使用ServerSocket类创建一个web服务器:(java) windows下的基于tcp的socket编程( ...
- 基于TCP的大文件传输c语言项目
文章目录 前言:功能实现 tcp文件传输的基本过程: 1.用户登录 1.1创建数据库 2.文件普通下载和上传的实现: 2.1 普通下载 2.2 普通上传 2.3 文件秒上传的实现 2.断点下载和断点上 ...
最新文章
- 如何在使用新技术前评估其浏览器兼容性
- LaTex 各种特殊符号
- 练习1-17 编写一个程序,打印长度大于80个字符的所有输入行.
- MAC下MongoDB的安装启动及停止
- 会打乒乓球的机器人!
- 前端学习(1436):vue特点
- ubuntu下python3及idle3的安装
- UnityGI2:Lightmaps
- 基于WF的意见征集6(浅析)
- java dvd集合框架_JAVA 集合框架
- 无线网络安全技术基础
- BIOS报警声_文伟_新浪博客
- 【GPU精粹与Shader编程】(二) 《GPU Gems 1》全书核心内容提炼总结 · 上篇
- MacOS 利用keka.app压缩工具制作dmg文件
- 雨夜赶长路,房企必经的三场“价值战事”
- Vue使用自定义字体
- html 颜色 excel,Excel~常用颜色对照表
- 中国汽车无线通信模块行业市场供需与战略研究报告
- 重学Elasticsearch第6章 : SpringBoot整合RestHighLevelClient
- uva1626 括号序列