基于TCP的网络应用程序

        最近在看网络编程方面的知识,记一下笔记。


 Socket简介

        网络编程的实现可以有多种方式,Windows Socket 就是其中一种,比较 简单的实现方法。Socket 是连接应用程序与网络驱动程序的桥梁,Socket在应用程序中创建,通过绑定操作与驱动程序建立关系。此后,应用程序送给Socket 交给驱动程序向网络上发送出去。计算机从网络上收到与该Socket绑定的IP地址和端口号相关的数据后,由驱动程序交给Socket,应用程序便可从Socket中提取接收到的数据。网络应用程序就是这样通过socket进行数据的发送与接收的。


端口

为了标识通信实体中进行通信的进程(应用程序),TCP/IP 协议提出了协议端口(protocol port, 简称端口)的概念。

       端口是一种抽象的软件结构(包括一些数据结构和I/O缓冲区)。应用程序通过系统调用与某端口建立连接(binding)后,传输层伟给该端口的数据都被相应的进程所接收,相应进程发给传输层的数据都通过该端口输出。


        端口用一个整数型标识符来表示,即端口号,端口号跟协议相关,TCP/IP传输层的两个协议TCP和UDP是完全的两个软件模块,因此各自的端口号也相互独立。也就是说,基于TCP和UDP的不同的网络应用程序,它们可以拥有相同的端口号。端口使用一个16位的数字来表示,它的范围是0~65536,1024以下的疝号保留给预定义的服务。


客户机/服务器模式

        客户机/服务器模式: 在TCP/IP 网络应用中,通信的两个进程间相互作用的主要模式 是客户机/服务器模式(client/server),即客户向服务器提出请求,服务器接收到请求后,提供相应的服务。


        客户机/服务器模式在操作的过程中采取的是主动请求的方式。

      首先服务器方要先启动,并根据请求提供相应服务。  

         1. 打开通信通道并告知主机,它愿意在某一地址和端口号上接收客户请求。

         2.等待客户请求到达端口

         3.接收到重复服务请求,处理该请求并发送应答信号。接收到并发服务请求,要激活一个新的进程(或线程)来处理这个客户请求。新进程(或线程)处理此客户请求,并不需要对其他请求作出应答。服务完成后,关闭此新进程与客户的通信链路并终止。

         4.返回第二步,等待另一客户请求。

         5.关闭服务器。


          而客户方:

          1.打开一个通信通道,并连接到服务器所在主机的特定端口。

          2.向服务器发送服务请求报文,等待并接收应答;继续提出请求。

          3.请求结束后关闭通信通道并终止。



 基于TCP(面向连接)的socket编程

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

          1.创建套接字(socket).

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

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

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

          5.用返回的套接字和客户端进行通信(send/recv).

          6.返回,等待另一客户请请求。

          7.关闭套接字。

         

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

          1.创建套接字(socket)。

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

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

          4.关闭套接字。

   

           在服务器端,当调用accept函数时,程序就会等待,等待客户端调用connect函数发出连接请求,然后服务器端接受该请求,于是双方就建立了连接。之后。服务器端和客户就可以利用send 和recv 函数进行通信了。在客户端并不需要调用bind 函数, 因为服务器需要接收客户端的请求,所以必须告诉本地主机打算在哪个IP地址和端口上等待客户请求。因此必须调用 bind 函数来实现这一功能。而对客户端来说,当它发起连接请求,服务器端接受该请求后,在服务器端就保真了该客户端的IP地址和端口的信息。这样,对服务器端来说,一旦建立连接之后,实际上它已经保存了客户端的IP地址和端口号信息,因此就可以利用把返回的套接字调用send/recv函数与客户端进行通信。



//注 这里用于WinSock库中的函数,需要为程序链接相应的 ws2_32.lib 文件,VS2012 添加方法  菜单-项目-配置属性-链接器-输入-附加依赖项, 加入ws2_32.lib.  (在服务器端和客户端都要添加)。


建立空 Win32 Console Application 类型的空项目TCPSrv  和 空项目 TCPClient,  分别添加 源文件:TcpSrv.cpp 和 TcpCleint.cpp



代码:

//TCPSrv.cpp 

#include <Winsock2.h>
#include <stdio.h>

void main()
{
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;

	wVersionRequested = MAKEWORD(1,1);

	err = WSAStartup(wVersionRequested, &wsaData);   //根据socket版本,加载套接字库 
	if(err != 0)
	{
		return;
	}

	if(LOBYTE(wsaData.wVersion) != 1 ||     //低字节为主版本
		HIBYTE(wsaData.wVersion) != 1)      //高字节为副版本
	{
		WSACleanup();
		return;
	}

	printf("server is operating!");
	//创建用于监听的套接字
	SOCKET sockSrv = socket(AF_INET,SOCK_STREAM,0);

	SOCKADDR_IN addrSrv;     //定义sockSrv发送和接收数据包的地址
	addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_port = htons(6000);
	
	//绑定套接字, 绑定到端口
	bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
	//将套接字设为监听模式, 准备接收客户请求
	listen(sockSrv,5);   //最大队列数目为5

	SOCKADDR_IN addrClient;   //用来接收客户端的地址信息
	int len = sizeof(SOCKADDR);

	while(1)
	{
		//等待客户请求到来
		//在服务器端,当调用accept函数时,程序就会等待,等待客户端调用connect
		//函数发出连接请求,然后服务器端接受该求,于是双方就建立了连接。
		//然后服务器端和客户端就可以利用send 和recv函数进行通信了。

		//当客户端请求到来时,该函数接受该请求,建立连接,
//同时它将返回一个相对于当前这个新连接的一个套接字,
		//保存于sockConn变量中,然后利用这个套接字与客户端进行通信,
//而原来的套接字仍继续监听客户端的连接请求。
		SOCKET sockConn = accept(sockSrv,(SOCKADDR*)&addrClient,&len);
		char sendBuf[100];
		sprintf_s(sendBuf,"Welcome %s to 306 lab",inet_ntoa(addrClient.sin_addr));

		printf("%s\n",inet_ntoa(addrClient.sin_addr));
		//通过已连接的sockConn套接字发送数据
		send(sockConn,sendBuf,strlen(sendBuf)+1,0);
        
		char recvBuf[100];
		recv(sockConn,recvBuf,100,0);
		printf("%s\n",recvBuf);
		closesocket(sockConn);
	}
}





//TcpCleint.cpp
#include <Winsock2.h>
#include <stdio.h>

void main()
{
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;

	wVersionRequested = MAKEWORD(1,1);   //使用版本为1.1的套接字

	err = WSAStartup(wVersionRequested,&wsaData);
	if(err != 0)
	{
		return;
	}

	if(LOBYTE(wVersionRequested) !=1 ||
		HIBYTE(wVersionRequested != 1))
	{
		WSACleanup();
		return;
	}

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

	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[100];
	recv(sockClient,recvBuf,100,0);
	printf("%s\n",recvBuf);
	//发送数据
	send(sockClient,"This is lisi",strlen("This is lisi")+1, 0);
	//关闭套接字
	closesocket(sockClient);
	WSACleanup();
	system("pause");
}


结果:

Server:



Client:




socket的详细介绍:http://goodcandle.cnblogs.com/archive/2005/12/10/294652.aspx

  • 0
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值