0%

计算机网络实验一_Echo实验

计算机网络实验1_Echo实验

1.编写TCP Echo程序

  客户端向服务器发送一个字符串,服务器收到后向字符串里添加当前的时间,再发送回客户端。

客户端程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <error.h>
#define BUFLEN 2000 // 缓冲区大小
/*------------------------------------------------------------------------
* main - TCP client for TIME service
*------------------------------------------------------------------------
*/
int
main(int argc, char *argv[])
{
char *host = "127.0.0.1"; /* server IP to connect本地IP */
char *service = "50500"; /* server port to connect 端口号 */
struct sockaddr_in sin; /* an Internet endpoint address */
char buf[BUFLEN+1]; /* buffer for one line of text */
int sock; /* socket descriptor */
int cc; /* recv character count */

sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); //创建套接字,参数:因特网协议簇(family),流套接字,TCP协议
//返回:要监听套接字的描述符或INVALID_SOCKET
memset(&sin, 0, sizeof(sin)); // 从&sin开始的长度为sizeof(sin)的内存清0
sin.sin_family = AF_INET; // 因特网地址簇
sin.sin_addr.s_addr = inet_addr(host); // printf("%d\n",sin.sin_addr.s_addr); // 设置服务器IP地址(32位)
sin.sin_port = htons((unsigned short)atoi(service)); // 设置服务器端口号
int ret=connect(sock, (struct sockaddr *)&sin, sizeof(sin)); // 连接到服务器,第二个参数指向存放服务器地址的结构,第三个参数为该结构的大小,返回值为0时表示无错误发生,
printf("请输入要发送的消息:");
scanf("%s",buf);
int c1=send(sock,buf,strlen(buf),0);
cc = recv(sock, buf, BUFLEN, 0); // 第二个参数指向缓冲区,第三个参数为缓冲区大小(字节数),第四个参数一般设置为0,返回值:(>0)接收到的字节数,(=0)对方已关闭,(<0)连接出错
if(cc<=0)
printf("Error!\n"); //出错或对方关闭(==0)。其后必须关闭套接字sock。
else if(cc > 0) {
buf[cc] = '\0'; // ensure null-termination
printf("\n客户端:\n收到的消息:%s\n",buf); // 显示所接收的字符串
}
close(sock); // 关闭监听套接字

printf("按回车键继续...");
getchar(); // 等待任意按键
}

服务器程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/* server2.c */
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

int main(int argc, char *argv[])
/* argc: 命令行参数个数, 例如:C:\> TCPServer 8080
argc=2 argv[0]="TCPServer",argv[1]="8080" */
{
struct sockaddr_in fsin; /* the from address of a client */
int msock, ssock; /* master & slave sockets */
char *service = "50500";
struct sockaddr_in sin; /* an Internet endpoint address */
int alen; /* from-address length */
char pts[1000]; /* pointer to time string */
time_t now; /* current time */

msock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); // 创建套接字,参数:因特网协议簇(family),流套接字,TCP协议
// 返回:要监听套接字的描述符或INVALID_SOCKET

memset(&sin, '\0', sizeof(sin)); // 从&sin开始的长度为sizeof(sin)的内存清0
sin.sin_family = AF_INET; // 因特网地址簇(INET-Internet)
sin.sin_addr.s_addr = INADDR_ANY; // 监听所有(接口的)IP地址。
sin.sin_port = htons((unsigned short)atoi(service)); // 监听的端口号。atoi--把ascii转化为int,htons--主机序到网络序(host to network,s-short 16位)
bind(msock, (struct sockaddr *)&sin, sizeof(sin)); // 绑定监听的IP地址和端口号

listen(msock, 5); // 建立长度为5的连接请求队列,并把到来的连接请求加入队列等待处理。

while (1)
{ // 检测是否有按键,如果没有则进入循环体执行
alen = sizeof(struct sockaddr); // 取到地址结构的长度
ssock = accept(msock, (struct sockaddr *)&fsin, (socklen_t *)&alen); // 如果在连接请求队列中有连接请求,则接受连接请求并建立连接,返回该连接的套接字,否则,本语句被阻塞直到队列非空。fsin包含客户端IP地址和端口号
time_t t = time(NULL);
char ch[64] = {0};
char result[100] = {0};
strftime(ch, sizeof(ch) - 1, "%Y-%m-%d--%H:%M:%S\n", localtime(&t));
int c1 = sprintf(pts, "%s",ch);
int c2 = recv(ssock, pts + c1, 1000, 0);
pts[c1 + c2] = '\0';
printf("\n服务器端:\n收到消息:%s\n收到消息的时间:%s", pts + c1,ch);
int cc = send(ssock, pts, strlen(pts), 0); // 第二个参数指向发送缓冲区,第三个参数为要发送的字节数,第四个参数一般置0,返回值为实际发送的字节数,出错或对方关闭时返回SOCKET_ERROR。
// printf("%s", pts); // 显示发送的字符串
close(ssock); // 关闭连接套接字
}
close(msock); // 关闭监听套接字
}

效果展示

客户端
image.png
image.png

服务器
image.png

2.编写TCP echo增强程序

  服务器在收到客户端的消息时显示服务器的当前时间、客户端的IP地址、客户端的端口号和客户端发来的信息,并把它们一并返回给客户端。
  客户端在发送消息后把服务器发回给它的消息显示出来。客户端程序与(1)同,不用修改
  要求服务器直接从accept()的参数fsin中得到客户端的IP地址和端口号。注:服务器获取IP地址后要求直接使用s_un_b的四个分量得到IP地址,不能使用函数inet_ntoa()转换IP地址。

客户端程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/* client2.c */
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <error.h>

#define BUFLEN 2000 // 缓冲区大小
/*------------------------------------------------------------------------
* main - TCP client for TIME service
*------------------------------------------------------------------------
*/
int
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 sin; /* an Internet endpoint address */
char buf[BUFLEN+1]; /* buffer for one line of text */
int sock; /* socket descriptor */
int cc; /* recv character count */

sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); //创建套接字,参数:因特网协议簇(family),流套接字,TCP协议
//返回:要监听套接字的描述符或INVALID_SOCKET
memset(&sin, 0, sizeof(sin));// 从&sin开始的长度为sizeof(sin)的内存清0
sin.sin_family = AF_INET; // 因特网地址簇
sin.sin_addr.s_addr = inet_addr(host); // printf("%d\n",sin.sin_addr.s_addr); // 设置服务器IP地址(32位)
sin.sin_port = htons((unsigned short)atoi(service)); // 设置服务器端口号
int ret=connect(sock, (struct sockaddr *)&sin, sizeof(sin)); // 连接到服务器,第二个参数指向存放服务器地址的结构,第三个参数为该结构的大小,返回值为0时表示无错误发生,
printf("请输入要发送的消息:");
scanf("%s",buf);
int c1=send(sock,buf,strlen(buf),0);
cc = recv(sock, buf, BUFLEN, 0); // 第二个参数指向缓冲区,第三个参数为缓冲区大小(字节数),第四个参数一般设置为0,返回值:(>0)接收到的字节数,(=0)对方已关闭,(<0)连接出错
if(cc<=0)
printf("Error!\n"); //出错或对方关闭(==0)。其后必须关闭套接字sock。
else if(cc > 0) {
buf[cc] = '\0'; // ensure null-termination
printf("\n客户端:\n收到的消息:%s\n",buf); // 显示所接收的字符串
}
close(sock); // 关闭监听套接字

printf("按回车键继续...");
getchar(); // 等待任意按键
}

服务器程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

int main(int argc, char *argv[])
/* argc: 命令行参数个数, 例如:C:\> TCPServer 8080
argc=2 argv[0]="TCPServer",argv[1]="8080" */
{
struct sockaddr_in fsin; /* the from address of a client */
int msock, ssock; /* master & slave sockets */
char *service = "50500";
struct sockaddr_in sin; /* an Internet endpoint address */
int alen; /* from-address length */
char pts[1000]; /* pointer to time string */
time_t now; /* current time */

msock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); // 创建套接字,参数:因特网协议簇(family),流套接字,TCP协议
// 返回:要监听套接字的描述符或INVALID_SOCKET

memset(&sin, '\0', sizeof(sin)); // 从&sin开始的长度为sizeof(sin)的内存清0
sin.sin_family = AF_INET; // 因特网地址簇(INET-Internet)
sin.sin_addr.s_addr = INADDR_ANY; // 监听所有(接口的)IP地址。
sin.sin_port = htons((unsigned short)atoi(service)); // 监听的端口号。atoi--把ascii转化为int,htons--主机序到网络序(host to network,s-short 16位)
bind(msock, (struct sockaddr *)&sin, sizeof(sin)); // 绑定监听的IP地址和端口号

listen(msock, 5); // 建立长度为5的连接请求队列,并把到来的连接请求加入队列等待处理。

while (1)
{ // 检测是否有按键,如果没有则进入循环体执行
alen = sizeof(struct sockaddr); // 取到地址结构的长度
ssock = accept(msock, (struct sockaddr *)&fsin, (socklen_t *)&alen); // 如果在连接请求队列中有连接请求,则接受连接请求并建立连接,返回该连接的套接字,否则,本语句被阻塞直到队列非空。fsin包含客户端IP地址和端口号
time_t t = time(NULL);
char ch[64] = {0};
char result[100] = {0};
strftime(ch, sizeof(ch) - 1, "%Y-%m-%d %H:%M:%S\n", localtime(&t));
memset(pts,0,sizeof(pts));
int c1 = recv(ssock, pts, 1000, 0);
/* int c1 = sprintf(pts + c2, "\n%s", fsin.sin_port,
fsin.sin_addr.S_un.S_un_b.s_b1,
fsin.sin_addr.S_un.S_un_b.s_b2,
fsin.sin_addr.S_un.S_un_b.s_b3,
fsin.sin_addr.S_un.S_un_b.s_b4,
);*/
unsigned int tem=fsin.sin_addr.s_addr;
printf("收到消息: %s\n收到时间: %s客户端IP地址: %d.%d.%d.%d\n 客户端端口号:%d\n"
,pts,ch,(tem<<24)>>24,(tem<<16)>>24,(tem<<8)>>24,tem>>24,fsin.sin_port);
char tempts[100];
strcpy(tempts,pts);
tempts[strlen(pts)]='\0';
sprintf(pts,"\n内容: %s\n时间: %s客户端IP地址: %d.%d.%d.%d\n客户端端口号: %d\n",
tempts,ch,(tem<<24)>>24,(tem<<16)>>24,(tem<<8)>>24,tem>>24,fsin.sin_port);
// pts[c1 + c2] = '\0';
// printf("\n服务器端:\n收到消息:%s\n收到消息的时间:%s", pts + c1, ch);
int cc = send(ssock, pts, strlen(pts), 0); // 第二个参数指向发送缓冲区,第三个参数为要发送的字节数,第四个参数一般置0,返回值为实际发送的字节数,出错或对方关闭时返回SOCKET_ERROR。
}
close(msock); // 关闭监听套接字
}

效果展示

客户端程序:
asf.png

服务器程序:
ang.png

3.编写UDP Echo增强程序

  
  完成Echo功能,即当客户端发来消息时,服务器显示出服务器的当前时间、客户端的IP、客户端的端口号和客户发来的信息,并把它们一并发回给客户端,客户端然后把它们显示出来。
  服务器可以直接从recvfrom()的参数from中得到客户端的IP地址和端口号,并且服务器用sendto()发回给客户端消息时可以直接用该参数from作为参数toAddr。可以使用inet_ntoa()转换客户端IP地址。
  客户端程序的recvfrom()可以直接使用原来sendto使用的sock。该sock已经绑定了客户端的IP地址和端口号,客户端可以直接用来接收数据。

客户端程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <string.h>
#include <netinet/in.h>
#define DEFAULT_IP "127.0.0.1"
#define DEFAULT_PORT "54321"

int main()
{
char buf[1024];
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(atoi(DEFAULT_PORT));
local.sin_addr.s_addr = inet_addr(DEFAULT_IP);
socklen_t len = sizeof(local);
int sock = socket(AF_INET, SOCK_DGRAM, 0);
printf("输入消息:\n");
scanf("%s", buf);
int s1 = sendto(sock, buf, strlen(buf), 0, (struct sockaddr *)&local, len);
int r = recvfrom(sock, buf, sizeof(buf) - 1, 0, (struct sockaddr *)&local, &len);
printf("%s\n ", buf);
printf("按任意键退出:\n");
getchar();
return 0;
}

服务器程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <arpa/inet.h>
#include <string.h>
#include <netinet/in.h>
#define DEFAULT_IP "127.0.0.1"
#define DEFAULT_PORT "54321"

int main()
{
int sock = socket(AF_INET, SOCK_DGRAM, 0);
char buf[1024];
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(atoi(DEFAULT_PORT));
local.sin_addr.s_addr = inet_addr(DEFAULT_IP);
bind(sock, (struct sockaddr *)&local, sizeof(local));
while (1)
{

struct sockaddr_in client;

socklen_t len = sizeof(client);
// printf("get a new client ,%s:%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
int r = recvfrom(sock, buf, sizeof(buf) - 1, 0, (struct sockaddr *)&client, &len);
// puts("??");
time_t t = time(NULL);
char ch[64] = {0};
strftime(ch, sizeof(ch) - 1, "%Y-%m-%d %H:%M:%S\n", localtime(&t));
unsigned int tem = client.sin_addr.s_addr;
char tempts[1024];
strcpy(tempts, buf);
// printf("%d\n",strlen(buf));
tempts[strlen(buf)] = '\0';
r = sprintf(buf, "\n客户端的消息: %s\n客户端IP地址: %d.%d.%d.%d\n时间: %s客户端端口号: %d\n",
tempts, (tem << 24) >> 24, (tem << 16) >> 24, (tem << 8) >> 24, tem >> 24, ch, client.sin_port);
// puts("??");
buf[r] = '\0';
printf("%s", buf);
int s = sendto(sock, buf, r, 0, (struct sockaddr *)&client, len);
memset(buf, 0, sizeof(buf));
}
return 0;
}

效果展示

客户端程序
aw.png

服务器程序
gweew.png