计算机网络-Echo实验(附源码)

【实验题目】Echo实验
【实验目的】掌握套节字的基本使用方法。
【实验内容】
(1)编写TCP Echo程序
实验要求:
服务器把客户端发送来的任何消息都返回给客户端,返回的消息前面要加上服务器的当前时间。客户端把返回的消息显示出来。客户端每输入一条消息就建立TCP连接,并把消息发送给服务器,在收到服务器回应后关闭连接。
1、只运行客户端程序而不运行服务器程序会出现什么错误,截屏说明原因。
计算机网络-Echo实验(附源码)_第1张图片
客户端调用connect()函数,向服务器进程发出连接请求,但服务器并没有运行,所以返回连接错误提示。
2、服务器如何可以退出循环?
客户端输入“exit”,结束服务器循环。如图:
客户端:此时客户端输入“exit
计算机网络-Echo实验(附源码)_第2张图片
服务端:结束循环
计算机网络-Echo实验(附源码)_第3张图片
2、 截屏(ctrl+alt+PrintScreen)服务器和客户端的运行结果(注明客户端和服务器):
客户端(两次运行)
计算机网络-Echo实验(附源码)_第4张图片
计算机网络-Echo实验(附源码)_第5张图片
服务端:
计算机网络-Echo实验(附源码)_第6张图片

(2)、编写TCP Echo增强程序
实验要求:
在(1)的基础上,服务器在收到客户端的消息时显示服务器的当前时间、客户端的IP地址、客户端的端口号和客户端发来的信息,并把它们一并返回给客户端。
客户端在发送消息后把服务器发回给它的消息显示出来。*客户端程序与(1)同,不用修改

要求服务器直接从accept()的参数fsin中得到客户端的IP地址和端口号。注:服务器获取IP地址后要求直接使用s_un_b的四个分量得到IP地址,不能使用函数inet_ntoa()转换IP地址。

截屏服务器和客户端的运行结果(注明客户端和服务器):
客户端(两次)
计算机网络-Echo实验(附源码)_第7张图片
计算机网络-Echo实验(附源码)_第8张图片
服务端:
计算机网络-Echo实验(附源码)_第9张图片
(3)编写UDP Echo增强程序
实验要求:
修改UDP例程,完成Echo功能,即当客户端发来消息时,服务器显示出服务器的当前时间、客户端的IP、客户端的端口号和客户发来的信息,并把它们一并发回给客户端,客户端然后把它们显示出来。
服务器可以直接从recvfrom()的参数from中得到客户端的IP地址和端口号,并且服务器用sendto()发回给客户端消息时可以直接用该参数from作为参数toAddr。可以使用inet_ntoa()转换客户端IP地址。
客户端程序的recvfrom()可以直接使用原来sendto使用的sock。该sock已经绑定了客户端的IP地址和端口号,客户端可以直接用来接收数据。

1、只运行客户端程序而不运行服务器程序会出现什么错误,截屏并说明原因。
计算机网络-Echo实验(附源码)_第10张图片服务器未运行,服务器没有把它们一并发回给客户端,客户端无法显示IP地址,且程序没有停止。

2、截屏服务器和客户端的运行结果(注明客户端和服务器):
客户端:
计算机网络-Echo实验(附源码)_第11张图片
计算机网络-Echo实验(附源码)_第12张图片
服务端:
计算机网络-Echo实验(附源码)_第13张图片
源码:
TCP服务端:

#include   
#include 
#include 
#include   
#pragma comment(lib,"ws2_32.lib")    //把ws2_32.lib加到Link页的连接库  
#define PORT 15001                    //通信的端口(指服务器端)
#define ERROR 0  
#define BUFFER_SIZE 1024            //注意:此Server端数据接收缓冲区 >= Client端数据发送缓冲区 ,否则造成缓冲区溢出
/*
	服务端原理:
		1、服务器进程创建套接字
		2、将本地地址绑定到所创建的套接字上,以三元组{<通信协议>,,<端口号>}在网络上标识该套接字
		3、将套接字置入监听模式,并准备接受连接请求
*/
void tran(int ip1, int ip2, int ip3, int ip4, char dest[])
{
	int cnt = 0;
	char des[100];
	if (ip4 == 0) {
		des[cnt++] = '0';
	}

	while (ip4)
	{
		des[cnt++] = ip4 % 10 + '0';
		ip4 /= 10;
	}
	des[cnt++] = '.';

	if (ip3 == 0) {
		des[cnt++] = '0';
	}
	while (ip3)
	{
		des[cnt++] = ip3 % 10 + '0';
		ip3 /= 10;
	}
	des[cnt++] = '.';

	if (ip2 == 0) {
		des[cnt++] = '0';
	}
	while (ip2)
	{
		des[cnt++] = ip2 % 10 + '0';
		ip2 /= 10;
	}
	des[cnt++] = '.';

	if (ip1 == 0) {
		des[cnt++] = '0';
	}
	while (ip1)
	{
		des[cnt++] = ip1 % 10 + '0';
		ip1 /= 10;
	}
	for (int i = 0; i < cnt; ++i)
	{
		dest[cnt - 1 - i] = des[i];
	}
	dest[cnt] = '\0';
}
void tran2(unsigned short int a, char c[])
{
	int i = 1;
	int x = a / 10;
	while (x)
	{
		i++;
		x = x / 10;
	}
	for (int j = i - 1; j >= 0; j--)
	{
		int b = a % 10;
		c[j] = b + '0';
		a = a / 10;
	}
	c[i] = '\0';
}
int main()
{
	char c[BUFFER_SIZE];
	char *pts; /* pointer to time string */
	time_t now;
	WSADATA WSAData;
	if (WSAStartup(MAKEWORD(2, 0), &WSAData) == SOCKET_ERROR)  //启动winsock ,WSAStartup()函数对Winsock DLL进行初始化
	{
		printf("Socket initialize fail!\n");
		exit(1);
	}
	else
	{
		printf("服务器已启动!\n\n");
	}
	SOCKET sock;                                        //服务进程创建套接字句柄(用于监听)
	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == ERROR)        //调用socket()函数创建一个流套接字,参数(网络地址类型,套接字类型,网络协议)
	{
		printf("Socket create!\n");
		WSACleanup();
		exit(1);
	}
	struct sockaddr_in ServerAddr;            //sockaddr_in结构用来标识TCP/IP协议下的地址,可强制转换为sockaddr结构
	ServerAddr.sin_family = AF_INET;            //sin_family字段必须设为AF_INET,表示该Socket处于Internet域
	ServerAddr.sin_port = htons(PORT);        //sin_port字段用于指定服务端口,注意避免冲突
	ServerAddr.sin_addr.s_addr = INADDR_ANY;  //sin_addr字段用于把一个IP地址保存为一个4字节的数,无符号长整型,根据不同用法还可表示本地或远程IP地址
	if (bind(sock, (LPSOCKADDR)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR)  //调用bind()函数将本地地址绑定到所创建的套接字上,以在网络上标识该套接字
	{
		printf("Bind fail!\n");
		closesocket(sock);
		WSACleanup();
		exit(1);
	}
	//printf("Server Socket Port:%d\n", ntohs(ServerAddr.sin_port));
	if (listen(sock, 10) == SOCKET_ERROR)        //调用listen()函数将套接字置入监听模式并准备接受连接请求,参数(已捆绑未连接的套接字描述字,正在等待连接的最大队列长度)
	{
		printf("Listen fail!\n");
		closesocket(sock);
		WSACleanup();
		exit(1);
	}

	SOCKET msgsock;            //创建一个新的套接字(用于接收accept函数的返回值,即表示已经接受的那个客户端的连接,进而接收Client发来的数据)
	char buf[BUFFER_SIZE];  //数据接收缓冲区
	while (1)
	{
		int alen = sizeof(struct sockaddr);
		
		if ((msgsock = accept(sock, (struct sockaddr *)&ServerAddr, &alen)) == INVALID_SOCKET)  //进入监听状态后,调用accept()函数接收客户端的连接请求,并把连接传给msgsock套接字,原sock套接字继续监听其他客户机连接请求
		{
			printf("Accept fail!\n");
			continue;
		}
		memset(buf, 0, sizeof(buf));                                            //初始化数据接收缓冲区
		recv(msgsock, buf, BUFFER_SIZE, 0);                                    //接收客户端发送过来的数据  
		if (buf[0] == 'e' && buf[1] == 'x' && buf[2] == 'i' && buf[3] == 't')        //"exit"命令,退出程序
		{
			printf("The End.\n");
			break;
		}
		(void)time(&now); // 取得系统时间
		pts = ctime(&now);
		printf("收到消息:%s", buf);
		printf("收到时间:%s", pts);
		send(msgsock, buf, BUFFER_SIZE, 0);
		send(msgsock, pts, BUFFER_SIZE, 0);
		printf("客户端IP地址:%d.%d.%d.%d\n", ServerAddr.sin_addr.S_un.S_un_b.s_b1, ServerAddr.sin_addr.S_un.S_un_b.s_b2, ServerAddr.sin_addr.S_un.S_un_b.s_b3, ServerAddr.sin_addr.S_un.S_un_b.s_b4);
		printf("客户端端口号:%d\n\n\n", ServerAddr.sin_port);
		tran(ServerAddr.sin_addr.S_un.S_un_b.s_b1, ServerAddr.sin_addr.S_un.S_un_b.s_b2, ServerAddr.sin_addr.S_un.S_un_b.s_b3, ServerAddr.sin_addr.S_un.S_un_b.s_b4, c);
		send(msgsock, c, BUFFER_SIZE, 0);
		tran2(ServerAddr.sin_port, c);
		send(msgsock, c, BUFFER_SIZE, 0);
		printf("\n\n");
		closesocket(msgsock);
	}

	closesocket(sock); //关闭套接字  
	WSACleanup();       //终止对Winsock DLL的使用,并释放资源
	return 0;
}

TCP客户端:

#include   
#include   
#pragma comment(lib,"ws2_32.lib")    //把ws2_32.lib加到Link页的连接库  
//#define IP "172.18.68.243"            //在两台计算机上测试,IP为Server端的IP地址  
#define IP "127.0.0.1"                //在一台计算机上测试,IP为本地回送地址
#define PORT 15001                    //注意:客户端设置通信的端口 = 服务端的端口
#define BUFFER_SIZE 1024            //数据发送缓冲区大小

int main()
{
	char buf1[BUFFER_SIZE];
	char buf2[BUFFER_SIZE];
	char buf3[BUFFER_SIZE];
	char buf4[BUFFER_SIZE];
	//const char *host = "127.0.0.1";
	char buf[BUFFER_SIZE];                                //buf数组存放客户端发送的消息  
	int inputLen;                                        //用于输入字符自增变量
	
	
		printf("输入要发送的信息:");
		inputLen = 0;
		memset(buf, 0, sizeof(buf));
		while ((buf[inputLen++] = getchar()) != '\n')        //输入以回车键为结束标识
		{
			;
		}
		

		WSADATA WSAData;
		if (WSAStartup(MAKEWORD(2, 0), &WSAData) == SOCKET_ERROR)  //WSAStartup()函数对Winsock DLL进行初始化
		{
			printf("Socket initialize fail!\n");
			
		}
		SOCKET sock;                                            //客户端进程创建套接字
		if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)  //创建流套接字(与服务端保持一致)
		{
			printf("Socket create fail!\n");
			WSACleanup();
			
		}

		struct sockaddr_in ClientAddr;                //sockaddr_in结构用来标识TCP/IP协议下的地址,可强制转换为sockaddr结构
		ClientAddr.sin_family = AF_INET;                //指Internet域
		ClientAddr.sin_port = htons(PORT);            //指定服务端所预留的端口
		ClientAddr.sin_addr.s_addr = inet_addr(IP);    //指定服务端所绑定的IP地址
		if (connect(sock, (struct sockaddr *)&ClientAddr, sizeof(ClientAddr)) == SOCKET_ERROR)  //调用connect()函数,向服务器进程发出连接请求  
		{
			printf("Connect fail!\n");
			closesocket(sock);
			WSACleanup();
			
		}
		else
		{
			send(sock, buf, BUFFER_SIZE, 0);  //向服务器发送数据 
			if (buf[0] == 'e' && buf[1] == 'x' && buf[2] == 'i' && buf[3] == 't')
			{
				printf("The End.\n");

			}
			else {
				recv(sock, buf1, BUFFER_SIZE, 0);
				recv(sock, buf2, BUFFER_SIZE, 0);
				recv(sock, buf3, BUFFER_SIZE, 0);
				recv(sock, buf4, BUFFER_SIZE, 0);
				printf("\n\n");
				printf("收到信息:");
				printf("%s", buf1);
				printf("收到时间:");
				printf("%s", buf2);
				printf("客户端IP地址:");
				printf("%s\n", buf3);
				printf("客户端端口号:");
				printf("%s\n", buf4);
				printf("\n\n");
			}
		}
		closesocket(sock);                             //关闭套接字
		WSACleanup();                                //终止对Winsock DLL的使用,并释放资源,以备下一次使用
	
	return 0;
}

UDP客户端:

#include 
#include 
#include 
#include 

#define	BUFLEN		2000                  // 缓冲区大小
#define WSVERS		MAKEWORD(2, 2)        // 指明版本2.2 
#pragma comment(lib,"ws2_32.lib")         // 加载winsock 2.2 Llibrary

void main(int argc, char *argv[])
{
	char	*host = "127.0.0.1";	    /* server IP to connect         */
	char	*service = "50500";  	    /* server port to connect       */
	struct sockaddr_in toAddr;	        /* an Internet endpoint address	*/
	int    size = sizeof(toAddr);
	char	buf[BUFLEN+1];  /* buffer for one line of text	*/
	char    buf1[BUFLEN + 1];
	char    buf2[BUFLEN + 1];
	char    buf3[BUFLEN + 1];
	SOCKET	sock;		  	            /* socket descriptor	    	*/
	int cc1;
	int	cc;			                    /* recv character count		    */
	char	*pts;			            /* pointer to time string	    */
	time_t	now;			            /* current time			        */

	WSADATA wsadata;
    WSAStartup(WSVERS, &wsadata);       /* 启动某版本Socket的DLL        */	

    sock = socket(PF_INET, SOCK_DGRAM,IPPROTO_UDP);

	memset(&toAddr, 0, sizeof(toAddr));
	toAddr.sin_family = AF_INET;
	toAddr.sin_port = htons((u_short)atoi(service));    //atoi:把ascii转化为int. htons:主机序(host)转化为网络序(network), s--short
	toAddr.sin_addr.s_addr = inet_addr(host);           //如果host为域名,需要先用函数gethostbyname把域名转化为IP地址


	memset(buf,'\0',BUFLEN);  //fill 1000 bytes with 'e'
	//buf[BUFLEN] = '\0';
    (void) time(&now);                                      // 取得系统时间
    pts = ctime(&now);                                      // 把时间转换为字符串
    memcpy(buf,pts,strlen(pts));
	printf("时间:");
	printf("%s", buf);
	int inputLen = 0;
	 cc=sendto(sock, buf, BUFLEN, 0,(SOCKADDR *)&toAddr, sizeof(toAddr));
	
		printf("输入消息:");
		scanf("%s", buf1);
		sendto(sock, buf1, BUFLEN, 0, (SOCKADDR *)&toAddr, sizeof(toAddr));

		printf("客户端IP地址:");
		recvfrom(sock, buf2, BUFLEN, 0, (SOCKADDR *)&toAddr, &size);
		printf("%s\n", buf2);

		printf("客户端端口号:");
		recvfrom(sock, buf3, BUFLEN, 0, (SOCKADDR *)&toAddr, &size);
		printf("%s\n\n", buf3);

	
	
	closesocket(sock);
	WSACleanup();       	          /* 卸载某版本的DLL */  
	printf("按任意键退出...");
	getchar();

}

UDP服务端:

#include 
#include 
#include 
#include "conio.h"


#define	BUFLEN		2000                  // 缓冲区大小
#define WSVERS		MAKEWORD(2, 2)        // 指明版本2.2 
#pragma comment(lib,"ws2_32.lib")         // 加载winsock 2.2 Llibrary


void tran2(unsigned short int a, char c[])
{
	int i = 1;
	int x = a / 10;
	while (x)
	{
		i++;
		x = x / 10;
	}
	for (int j = i - 1; j >= 0; j--)
	{
		int b = a % 10;
		c[j] = b + '0';
		a = a / 10;
	}
	c[i] = '\0';
}
void main(int argc, char *argv[])
{
	char   *host = "127.0.0.1";	    /* server IP Address to connect */
	char   *service = "50500";  	    /* server port to connect       */
	struct sockaddr_in sin;	        /* an Internet endpoint address	*/
	struct sockaddr_in from;        /* sender address               */
	int    fromsize = sizeof(from);
	char   buf[BUFLEN+1];   	    /* buffer for one line of text	*/
	SOCKET	sock;		  	        /* socket descriptor	    	*/
	int	cc;			                /* recv character count		    */
	char c[BUFLEN+1];
	WSADATA wsadata;
    WSAStartup(WSVERS, &wsadata);   /* 加载winsock library,WSVERS为请求版本,wsadata返回系统实际支持的最高版本。    */		
    sock = socket(PF_INET, SOCK_DGRAM,IPPROTO_UDP); // 创建UDP套接字, 参数:因特网协议簇(family),数据报套接字,UDP协议号, 返回:要监听套接字的描述符或INVALID_SOCKET
	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = INADDR_ANY;                     // 绑定(监听)所有的接口。
	sin.sin_port = htons((u_short)atoi(service));         // 绑定指定接口。atoi--把ascii转化为int,htons -- 主机序(host)转化为网络序(network), 为short类型。 
	bind(sock, (struct sockaddr *)&sin, sizeof(sin));     // 绑定本地端口号(和本地IP地址)

 	while(!_kbhit()){                                    //检测是否有按键
	    recvfrom(sock, buf, BUFLEN, 0, (SOCKADDR *)&from, &fromsize);  //接收客户数据。返回结果:cc为接收的字符数,from中将包含客户IP地址和端口号。
		printf("时间:");
		printf("%s", buf);

		recvfrom(sock, buf, BUFLEN, 0, (SOCKADDR *)&from, &fromsize);
		printf("客户端的消息:" );
		printf("%s\n", buf);

		printf("客户端IP地址:%s\n", inet_ntoa(from.sin_addr));
		printf("客户端端口号:%d\n\n\n", from.sin_port);

		
		//tran(from.sin_addr.S_un.S_un_b.s_b1, from.sin_addr.S_un.S_un_b.s_b2, from.sin_addr.S_un.S_un_b.s_b3, from.sin_addr.S_un.S_un_b.s_b4, c);
		sendto(sock, inet_ntoa(from.sin_addr), BUFLEN, 0, (SOCKADDR *)&from, sizeof(from));

		tran2(from.sin_port, c);
		sendto(sock, c, BUFLEN, 0, (SOCKADDR *)&from, sizeof(from));
		


	   
		
	}
	closesocket(sock);
	WSACleanup();       	          /* 卸载某版本的DLL */
	getchar();
}




你可能感兴趣的:(计算机网络)