基于TCP的socket套接字的网络编程(客户端/服务端模式)

卫金鑫

学号:20021210618 

学院:电子工程学院

转载自https://www.toutiao.com/a6634497030410469902/

【嵌牛导读】在诸多的网络互联协议中,TCP/IP 协议使用最为普通,也成为了事实上的网络工业标准。网际协议 IP和TCP是 TCP/IP 体系中两个最主要的协议之一。今天我们主要讲讲基于TCP的socket套接字的网络编程。

【嵌牛鼻子】TCP/IP 协议,socket套接字,网络编程

【嵌牛提问】你知道怎样基于TCP进行socket套接字网络编程吗?

【嵌牛正文】

由于相对独立的网络产品难以实现互联,国际标准化组织ISO于1984年颁布了一个"开放系统互联基本参考模型“的国际标准ISO 7498,简称OSI/RM,即著名的OSI七层模型。

OSI参考模型中,对等层协议之间交换的信息单元统称为协议数据单元(PDU,Protocl Data Unit)。OSI参考模型中每一层都要依靠下一层提供的服务。为了提供服务,下层把上层的PDU作为本层的数据封装,然后加入本层的头部(有的层还要加入尾部,例如数据链路层)。头部的数据中含有完成数据传输所需的控制信息。我们在寄信时,要把信件放到信封中,当收信人收到这封信时,他要打开信封,取出信件。这种数据自上而下递交的过程实际上就是不断封装的过程。到达目的地后自下而上递交的过程就是不断拆封的过程。由此可知,在物理线路上传输的数据,其外面实际上被封装了多层“信封”。但是,某一层只能识别由对等层封装的“信封”,而对于被封装在“信封”内部的数据仅仅是拆封后将其提交给上层,本层不作任何处理。

在诸多的网络互联协议中,TCP/IP 协议使用最为普通,也成为了事实上的网络工业标准。网际协议 IP和TCP是 TCP/IP 体系中两个最主要的协议之一。

一台计算机要向另一台计算机发送数据,首先必须将该数据打包,打包的过程称为封装。封装就是在数据前面加上特定的协议头部。例如,利用TCP协议发送数据时,当数据到达传输层时,就会加上TCP协议头,当该数据到达网络层时,在其前面还会加上IP协议头。

其中,从网络上下载文件时使用的是FTP协议,上网浏览网页时使用的是HTTP协议。DNS也是一种应用比较广泛的协议,我们在访问网络上一台主机时,通常不是直接输入对方的IP地址,而是输入这台主机的一个域名,例如访问新浪网时,通常会输入:www.sina.com.cn,这就是新浪网的域名,通过DNS服务就可以将这个域名解析为它所对应的IP地址,通过IP地址就可以访问新浪网的主机了;通过FoxMai丨发送电子邮件时,就会使用SMTP协议;利用FoxMail从邮件服务器(例如263)上收取电子邮件时,就会使用POP3协议。

TCP:面向连接的可靠的传输协议。利用TCP协议进行通信时,首先要通过三步握手,以建立通信双方的连接。一旦连接建立好,就可以进行通信了。TCP提供了数据确认和数据重传的机制,保证了发送的数据一定能到达通信的对方。这就与打电话一样,首先要拨打对方的电话号码以建立连接,一旦电话拨通,连接建立之后,你所说的每一句话都能够传送到通话的另一方。

UDP:是无连接的、不可靠的传输协议。采用UDP进行通信时,不需要建立连接,可以直接向一个IF地址发送数据,但是对方能否收到,就不敢保证了。我们知道在网络上传输的是电信号,既然是电信号,在传输过程中就会有衰减,因此数据有可能在网络上就消失了,也有可能我们所指定的1P地址还没有分配,或者该IP地址所对应的主机还没有运行,这些情况都有可能导致发送的数据接收不到。这就好像寄信的过程,我们所寄的信件有可能在运输的途中丢失,也有可能收信人搬家了,这都会导致信件的丢失。但另一方面,我们在寄信时不需要和对方认识,也就是说,不需要建立连接。例如,我给某个国家的领导人写了封信,想谈谈两国的关系,这封信能够寄出,但是能否到达就不好说了。既然UDP协议有这么多缺点,那么为什么还要使用它呢?这主要是因为UDP协议不需要建立连接,而且没有数据确认和重传机制,所以实时性较高。因此,在一些实时性要求较高的场合,例如视频会议,就可以釆用UDP协议来实现。因为对于这类应用来说,丢失少量数据并不会影响视频的观看。但对于数据完整性要求较高的场合,就应采用TCP协议。

IP网络层提供IP寻址和路由。因为在网络上数据可以经由多条线路到达目的地,网络层负责找出最佳的传输线路。

IP地址与数据包

IP层就是把数据分组从一个主机跨越千山万水搬运到另外一主机, 并且这搬运服务一点都不可靠, 丢包、重复、失序可以说是家常便饭。如果失败是否需要重传?如果需要,那就使用TCP协议实现可靠的、面向连接的传输连接,如果不需要,那就使用UDP协议使用不可靠的、不面向连接的传输连接。

所以不同的网络应用程序可以用TCP实现,也可以用UDP实现,只是可靠性和实时性不一样。

在TCP或UDP协议上编程是比较复杂的。例如TCP协议, 我们不能要求每个程序员都去实现建立连接的3次握手(确认客户端、服务端的发信、收信能力),分组交换、失败重传(中间节点的路由可以是随机的,允许失序、重复、丢失,可靠的传输完全由两端点来实现,失败后重传即可,而顺序可以由数据包的序号来确定), 这些应该是属于操作系统内核的部分, 没必要重复开发, 但是对于应用程序来讲, 操作系统可以抽象出一个socket概念, 让上层应用去编程。

所以,Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。


Socket是连接应用程序与网络驱动程序的桥梁,Socket在应用程序中创建,通过bind与驱动程序建立关系。此后,应用程序送给Socket的数据,由Socket交给驱动程序向网络上发送出去。计算机从网络上收到与该Socket绑定的IP+Port相关的数据后,由驱动程序交给Socket,应用程序便可从该Socket中提取接收到的数据。网络应用程序就是这样通过socket进行数据的发送与接收的。

基于TCP(面向连接)的socket编程的服务器端程序流程如下:

1 创建套接字(socket())。

2 将套接字绑定到一个本地地址和端口上(bind())。

3 将套接字设为监听模式,准备接收客户请求(listen())

4 等待客户请求到来;当清求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept())。

5 用返回的套接字和客户端进行通信(send/recv())返回,等待另一客户请求。

6 关闭套接字。

基于TCP(面向连接)的socket编程的客户端程序流程如下:

1 创建套接字(socket())。

2 向服务器发出连接请求(connect())。

3 和服务器端进行通信(send/recv())。

4 关闭套接字。




代码:

//tcp server

#include <Winsock2.h>

#include <stdio.h>

#pragma comment(lib,"ws2_32.lib")

void main(){

WORD wVersionRequested; // 指定准备加载的Winsock库版本

WSADATA wsaData; // Winsock库版本信息的结构体

wVersionRequested = MAKEWORD( 1, 1);

int err = WSAStartup( wVersionRequested, &wsaData ); // 加载套接字库

if ( err != 0 ) { return;}

if ( LOBYTE( wsaData.wVersion ) != 1 ||

HIBYTE( wsaData.wVersion ) != 1 ) {

WSACleanup( );

// 释放为该应用程序分配的资源,终止对WinSock动态库的使用

return;

}

SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);

// 创建套接字AF_INET表示TCP/IP协议

// SOCK_STREAM表示TCP连接,SOCK_DGRAM表示UDP连接

// 第三个参数为零表示自动选择协议

SOCKADDR_IN addrSrv; // 定义一个地址结构体的变量

addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);

addrSrv.sin_family=AF_INET;

addrSrv.sin_port=htons(6000);

//htons把一个u_short类型从主机字节序转换为网络字节序

bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)); //将套接字绑定到本地的某个地址和端口上

listen(sockSrv,5); //将指定的套接字设定为监听模式

SOCKADDR_IN addrClient;

int len=sizeof(SOCKADDR);

while(1) {

SOCKET sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len);

//接受客户端发送的连接请求

char sendBuf[100];

sprintf(sendBuf,"Welcome %s to here",inet_ntoa(addrClient.sin_addr));

send(sockConn,sendBuf,strlen(sendBuf)+1,0);

//通过一个已建立连接的套接字发送数据

char recvBuf[100];

recv(sockConn,recvBuf,100,0); /

/从一个已建立连接的套接字接收数据

printf("%s\n",recvBuf);

closesocket(sockConn);

}

}

//添加ws2_32.lib:工程→设置→连接,添加该库(前面要有空格)或

//#pragma comment(lib,"ws2_32.lib")



//Tcp client

#include <Winsock2.h>

#include <stdio.h>

#pragma comment(lib,"ws2_32.lib")

void main(){

WORD wVersionRequested; // 指定准备加载的Winsock库版本

WSADATA wsaData; // Winsock库版本信息的结构体

wVersionRequested = MAKEWORD( 1, 1);

int err = WSAStartup( wVersionRequested, &wsaData ); // 加载套接字库

if ( err != 0 ) { return;}

if ( LOBYTE( wsaData.wVersion ) != 1 ||

HIBYTE( wsaData.wVersion ) != 1 ) {

WSACleanup( );

// 释放为该应用程序分配的资源,终止对WinSock动态库的使用

return;

}

SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);

// 创建套接字。AF_INET表示TCP/IP协议

// SOCK_STREAM表示TCP连接,SOCK_DGRAM表示UDP连接

//第三个参数为零表示自动选择协议

SOCKADDR_IN addrSrv; //定义一个地址结构体的变量

addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");

addrSrv.sin_family = AF_INET;

addrSrv.sin_port = htons(6000);

connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));

//向服务器发出连接请求

char recvBuf[1000];

recv(sockClient,recvBuf,100,0); //接收数据

printf("%s\n",recvBuf);

send(sockClient,"Hello!",strlen("Hello!")+1,0); //发送数据

closesocket(sockClient); //关闭套接字

WSACleanup();

system("pause");

}

//添加ws2_32.lib:工程→设置→连接,添加该库(前面要有空格)或

//#pragma comment(lib,"ws2_32.lib")


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容