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

于数据完整性要求较高的场合,就应采用TCP协议。程序员

IP网络层提供IP寻址和路由。由于在网络上数据能够经由多条线路到达目的地,网络层负责找出最佳的传输线路。编程

IP地址与数据包:设计模式

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

 

IP层就是把数据分组从一个主机跨越千山万水搬运到另一主机, 而且这搬运服务一点都不可靠, 丢包、重复、失序能够说是屡见不鲜。若是失败是否须要重传?若是须要,那就使用TCP协议实现可靠的、面向链接的传输链接,若是不须要,那就使用UDP协议使用不可靠的、不面向链接的传输链接。服务器

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

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

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

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

 

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

基于TCP(面向链接)的socket编程的服务器端程序流程以下:设计

1 建立套接字(socket())。server

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

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

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

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

6 关闭套接字。

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

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

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

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

4 关闭套接字。

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

 

代码:

//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
",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
",recvBuf);
	
	send(sockClient,"Hello!",strlen("Hello!")+1,0);				//发送数据
	
	closesocket(sockClient);									//关闭套接字
	WSACleanup();
	system("pause");
}
//添加ws2_32.lib:工程→设置→链接,添加该库(前面要有空格)或
//#pragma comment(lib,"ws2_32.lib")

-End-