一、实验目的与要求:
(一)实验目的
该实验为设计性实验,实验目的如下:
- 了解本地计算机的网络配置。
- 熟悉面向对象编程/C编程环境,能够编写简单程序。
- 熟练网络查阅源代码资源并会调试,修改,测试。
(二)实验要求
- 本实验一人一组,编程语言为C/C++/C#/JAVA。
- 要求学生熟练掌握C/C++/C#/JAVA语言编程,多线程编程。
- 实验报告要求:
-
- 实验报告要求包括实验目的、实验要求、实验内容(系统的设计和实现)、实验结果分析和实验体会等,重点在于实验内容(系统的设计和实现)和实验结果分析。实验报告要求上传和打印。
- 写出系统设计和实现过程中的心得和体会,并回答实验中的思考题。
- 实验报告撰写规范请见附。
二、实验内容、步骤及结论
(一)实验内容
- 实现简单的基于TCP或UDP的通信程序(控制台和视窗都可以),要求使用VC/JAVA/C#编程。
- 对完成的socket通信进行安全性设置,4项任选2项实现(1.做用户验证(用户未注册或者密码不正确,就断开连接)2.加密信息内容3.超时机制4.黑名单机制)。
(二)代码:https://segmentfault.com/a/1190000000736700
1.服务器端server.c
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include "aes_options.h" //add
int main()
{
int server_fd;
int client_fd;
int len;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int sin_size;
char buffer[BUFSIZ];
// printf("%d",BUFSIZ);
memset(&server_addr, 0, sizeof(server_addr)); // initialize struct
memset(&server_addr, 0, sizeof(client_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(9000);
if ((server_fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) // create server socket
{
perror("socket create failed");
return 1;
}
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) < 0) // bind info on server socket
{
perror("bind failed");
return 1;
}
listen(server_fd, 5); // listen port 9000
sin_size = sizeof(struct sockaddr_in);
if ((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &sin_size)) < 0)
{
perror("accept failed");
return 1;
}
printf("accept client %s\n", inet_ntoa(client_addr.sin_addr));
len = send(client_fd, "Welcome to my server\n", 21, 0);
while ((len = recv(client_fd, buffer, BUFSIZ, 0)) > 0)
{
char *decryto_string = NULL; // add
decrypt(buffer, &decryto_string, len); // add
printf("%s \n", decryto_string);
if (send(client_fd, decryto_string, len, 0) < 0) // modified
{
perror("send failed");
return 1;
}
}
close(client_fd);
close(server_fd);
return 0;
}
2.客户端client.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include "aes_options.h" //add
int main()
{
int len;
int client_sockfd;
struct sockaddr_in server_addr;
char buffer[BUFSIZ];
char *encrypt_string = NULL;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons(9000);
if((client_sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket create failed");
return 1;
}
int username;
int password;
printf("enter the username:");
scanf("%d", &username);
printf("enter the password:");
scanf("%d", &password);
if (username !=2020 || password != 1212)
{
printf("uncorrect name!\n");
return 1;
}
if(connect(client_sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) < 0)
{
perror("connect failed");
return 1;
}
printf("connect to server\n");
len = recv(client_sockfd, buffer, BUFSIZ, 0);
buffer[len] = '\0';
printf("%s", buffer);
while(1)
{
printf("enter a data:");
scanf("%s", buffer);
if(!strcmp(buffer,"quit"))
break;
int encrypt_length = encrypt(buffer, &encrypt_string); //add
len = send(client_sockfd, encrypt_string, encrypt_length, 0); //add
len = recv(client_sockfd, buffer, BUFSIZ, 0);
buffer[len] = '\0';
printf("recived:%s \n", buffer);
}
close(client_sockfd);
printf("bye");
return 0;
}
/*char username;
int password;
printf("enter the username:");
scanf("%s", &username);
printf("enter the password:");
scanf("%d", &password);
if (username != "ycy" || password != 20201212)
{
printf("uncorrect name!\n");
return 1;
}
*/
3.加密解密函数openssl.c
#include <stdio.h>
#include <openssl/aes.h>
#include <stdlib.h>
#include <string.h>
int encrypt(char *input_string, char **encrypt_string)
{
AES_KEY aes;
unsigned char key[AES_BLOCK_SIZE]; // AES_BLOCK_SIZE = 16
unsigned char iv[AES_BLOCK_SIZE]; // init vector
unsigned int len; // encrypt length (in multiple of AES_BLOCK_SIZE)
unsigned int i;
// set the encryption length
len = 0;
if ((strlen(input_string) + 1) % AES_BLOCK_SIZE == 0)
{
len = strlen(input_string) + 1;
}
else
{
len = ((strlen(input_string) + 1) / AES_BLOCK_SIZE + 1) * AES_BLOCK_SIZE;
}
// Generate AES 128-bit key
for (i = 0; i < 16; ++i)
{
key[i] = 32 + i;
}
// Set encryption key
for (i = 0; i < AES_BLOCK_SIZE; ++i)
{
iv[i] = 0;
}
if (AES_set_encrypt_key(key, 128, &aes) < 0)
{
fprintf(stderr, "Unable to set encryption key in AES\n");
exit(0);
}
// alloc encrypt_string
*encrypt_string = (unsigned char *)calloc(len, sizeof(unsigned char));
if (*encrypt_string == NULL)
{
fprintf(stderr, "Unable to allocate memory for encrypt_string\n");
exit(-1);
}
// encrypt (iv will change)
AES_cbc_encrypt(input_string, *encrypt_string, len, &aes, iv, AES_ENCRYPT);
return len;
}
void decrypt(char *encrypt_string, char **decrypt_string, int len)
{
unsigned char key[AES_BLOCK_SIZE]; // AES_BLOCK_SIZE = 16
unsigned char iv[AES_BLOCK_SIZE]; // init vector
AES_KEY aes;
int i;
// Generate AES 128-bit key
for (i = 0; i < 16; ++i)
{
key[i] = 32 + i;
}
// alloc decrypt_string
*decrypt_string = (unsigned char *)calloc(len, sizeof(unsigned char));
if (*decrypt_string == NULL)
{
fprintf(stderr, "Unable to allocate memory for decrypt_string\n");
exit(-1);
}
// Set decryption key
for (i = 0; i < AES_BLOCK_SIZE; ++i)
{
iv[i] = 0;
}
if (AES_set_decrypt_key(key, 128, &aes) < 0)
{
fprintf(stderr, "Unable to set decryption key in AES\n");
exit(-1);
}
// decrypt
AES_cbc_encrypt(encrypt_string, *decrypt_string, len, &aes, iv,
AES_DECRYPT);
}
4.AES头文件aes_options.h
#ifndef _ASE_H_
#define _ASE_H_
int encrypt(char *input_string, char **encrypt_string);
void decrypt(char *encrypt_string, char **decrypt_string, int len);
#endif
(三)运行
gcc -I. openssl.c server.c -o server -lcrypto
gcc -I. openssl.c client.c -o client -lcrypto
先运行server,再运行client
输入quit退出
若用户名或密码错误,无法进入
三、实验体会
微信、QQ、手机APP在进行网络连接时有何种安全措施?
为了确保即时通讯的稳定性,采用了短链接(HTTP协议)和长链接(TCP协议)相结合的方式,分别应对状态协议和数据传输协议。短链接方式采用HTTP协议,主要用于用户登录信息验证、获取好友列表、用户头像、行为日志上报、刷新朋友圈等短期状态型的应用;长链接方式采用TCP协议,主要用于接收/发送文本消息、语音、图片、视频文件等传输过程需要保持连接状态的数据的传输。
微信采用SYNC协议,是参考Activesync来实现的。SYNC是基于状态同步的协议,将信息的收发过程看作状态同步的过程。服务器每收到最新的消息或更新好友状态,都会将客户端与服务端消息进行同步。微信平台将交互模式简单化,只需要推送一个消息到达的通知,终端通过收到的通知进行信息同步。这种简化模式有利于微信在各种平台上的应用,通过状态差值同步数据的方式,获得最小的数据变更。同时,采用增量的传输模式得到最小的数据传输量。采用SYNC协议,可以确保信息是稳定传送、按序到达的。