网络编程学习笔记二(实现一个基于简单TCP的用户注册程序)

时间:2021-08-02 23:54:43
•实现一个基于简单TCP的用户注册程序,实现下列功能
–客户端发送用户注册信息(用户名、密码和其他资料)到服务器端;
–服务器端首先检查用户注册数据是否符合格式。如不符合则返回“非法访问”提示;
–如符合检查用户文件中是否存在相同用户名,如不存在,则将用户注册信息存放到用户文件中,返回“用户注册成功”提示

如用户文件中存在相同用户名,则返回“用户名已被注册


客户端程序


#include <stdio.h>
#include <winsock.h>
#include<string.h>

#pragma comment(lib, "ws2_32.lib")//这句话的前面意思是静态加入一个lib文件也就是库文件ws2_32.lib文件,提供了对以下网络相关API的支持,若使用其中的API,则应该将ws2_32.lib加入工程(否则需要动态载入ws2_32.dll)。

int main(int argc, char *argv[])
{
	//int First,Second;
	//step 1: 初始化Windows Socket 2.2库
   	WSADATA						wsaData;//功能是:存放windows socket初始化信息
	WSAStartup(MAKEWORD(2,2), &wsaData);

	//step 2: 创建客户端SOCKET套接字
    SOCKET sClient = socket(AF_INET, SOCK_STREAM, 0);

	//step 3: 设置服务器地址
    sockaddr_in serverAddr;

	memset(&serverAddr, 0, sizeof(sockaddr_in));//去掉没有影响,暂时不知用途
	/*void *memset(void *s, int ch, size_t n);
	函数解释:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。
    memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法*/

    serverAddr.sin_family = AF_INET;
    //serverAddr.sin_addr.s_addr = inet_addr(argv[1]);
    //serverAddr.sin_port = htons((u_short)atoi(argv[2]));

    serverAddr.sin_addr.s_addr =inet_addr("127.0.0.1");
    //serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serverAddr.sin_port = htons(5150);

	//step 4: 连接服务器
    connect(sClient, (SOCKADDR *)&serverAddr, sizeof(serverAddr));//sockaddr和sockaddr_in的区别:二者的占用的内存大小是一致的,因此可以互相转化,从这个意义上说,他们并无区别

	//step 5:与服务器进行通讯
	printf("%s\n","正在启动用户注册程序:");
	while(1)
	{
		char data[1024]={0},buf[100]={0};
		//录入基本信息
		printf("%s","用户名(学号或8位字符串):");
		scanf("%s",data);
		printf("%s","密码(8-30字符):");
		scanf("%s",buf);
		strcat(data,"+");
		strcat(data,buf);
		printf("%s","姓名:");
		scanf("%s",buf);
		strcat(data,"+");
		strcat(data,buf);
		printf("%s","性别:");
		scanf("%s",buf);
		strcat(data,"+");
		strcat(data,buf);
		printf("%s","年龄:");
		scanf("%s",buf);
		strcat(data,"+");
		strcat(data,buf);
		//FILE *fp=fopen("use.txt","a");
		//fprintf(fp,"%s\n",data);
		//fclose(fp);
		send(sClient, data, strlen(data)+1, 0);//第三个参数是缓冲区中数据的长度,返回所发送的数据的总长度或SOCKET_ERROR错误
		recv(sClient, data, 1024, 0);//第三个参数是缓冲区的长度;成功执行时,返回接收到的字节数。另一端已关闭则返回0。失败返回-1
		printf("%s\n",data);
		recv(sClient, data, 1024, 0);
		printf("%s\n",data);
	}

	//step 6:关闭套接字
    closesocket(sClient);

    //step 7:释放Winsock库
    WSACleanup();
	getchar();
	getchar();
    return 0;
}


服务器端程序


#pragma comment(lib, "ws2_32.lib")//预编译
#include <stdio.h>
#include <winsock2.h>

int main(int argc, char *argv[])
{
	//step1:初始化Windows Socket 2.2库
	WSADATA              wsaData;
	WSAStartup(MAKEWORD(2,2), &wsaData);

	//step2:创建一个新的Socket来响应客户端的连接请求
	SOCKET sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	//step3:填写服务器地址信息
	int                  port = 5150;// 端口为5150
	SOCKADDR_IN          serverAddr;
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = htons(port);
	//serverAddr.sin_addr.s_addr =inet_addr("10.66.103.187");
	serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	//IP地址为INADDR_ANY,使用htonl将IP地址转换为网络格式

	//step4:绑定监听端口
	bind(sListen, (SOCKADDR *)&serverAddr, sizeof(serverAddr));

	//step5:开始监听,指定三次握手等待队列长度为5
	listen(sListen, 5);

	printf("开始监听......\n");

	while(true)
	{
		//step6:接受新的连接
		SOCKET	sNewConnection;
		SOCKADDR_IN clientAddr;
		memset(&clientAddr, 0, sizeof(clientAddr));
		int clientAddrLen = sizeof(clientAddr);
		sNewConnection = accept(sListen,
			(SOCKADDR *)&clientAddr, &clientAddrLen);

		//step7:新的连接建立后,就可以互相通信了,
		//在这个简单的例子中,
		//我们发送"Welcome to Network Programing!",然后关闭连接
        //进行数据交换
		while(1)
		{
			char message[1024]={0},buf[100]={0},messagebuf[1024]={0};//message收发信息,buf错误信息,操作messagebuf收发信息
			int i=0,j=0;//i标记是否成功注册,j标记用户名是否已存在
			int recvSize=recv(sNewConnection,message, sizeof(message), 0);//接收数据
			if(recvSize <= 0)//判断是否接收成功
                break;
            strcpy(messagebuf,message);//对messagebuf赋值

			//对接收的数据进行验证
			char *use,*pass,*name,*sex,*age;
			use=strtok(messagebuf,"+");
            pass=strtok(NULL,"+");
            name=strtok(NULL,"+");
            sex=strtok(NULL,"+");
            age=strtok(NULL,"+");
            printf("注册信息为:%s %s %s %s %s\n",use,pass,name,sex,age);
            strcpy(buf,"非法访问!");
            while(1)
            {
                if(strlen(use)!=8)
                {
                    i=1;
                    send(sNewConnection, buf, strlen(buf)+1, 0);
                    break;
                }

                if(!(strlen(pass)>7&&strlen(pass)<31))
                {
                    i=1;
                    send(sNewConnection, buf, strlen(buf)+1, 0);
                    break;
                }

                if(strcmp(sex,"男")&&strcmp(sex,"女"))
                {
                    i=1;
                    send(sNewConnection, buf, strlen(buf)+1, 0);
                    break;
                }
                strcpy(buf,"数据合法!");
                send(sNewConnection, buf, strlen(buf)+1, 0);
                break;
            }

            //检验是否注册
            FILE *fp = fopen("use.txt", "r");;
            while(!feof(fp)&&i==0)
            {
                char *used;
                char szTest[1000] = {0};
                fgets(szTest, sizeof(szTest) - 1, fp); // 包含了\n
                used=strtok(szTest,"+");
                if(!strcmp(use,used))
                {
                    j=1;
                    i=1;
                    break;
                }
            }
            fclose(fp);

            //如果未注册则保存
            if(i==0)
            {
                fp = fopen("use.txt", "a");
                fprintf(fp,"\n%s",message);
                fclose(fp);
                strcpy(buf,"注册成功!");
                send(sNewConnection, buf, strlen(buf)+1, 0);
            }
            else//如果数据不合法或者用户已存在则返回提示信息
            {
                if(j==1)
                {
                    strcpy(buf,"用户名已存在!");
                    send(sNewConnection, buf, strlen(buf)+1, 0);
                }
                else
                {
                    strcpy(buf,"注册失败!");
                    send(sNewConnection, buf, strlen(buf)+1, 0);
                }
            }
		}
		//关闭与客户通讯的套接字
		closesocket(sNewConnection);
		printf("%s\n","另一端关闭");
	}

	//step8:关闭套接字
	closesocket(sListen);
	//step9:释放Windows Socket DLL的相关资源
	WSACleanup();
	return 0;
}

最后结果


网络编程学习笔记二(实现一个基于简单TCP的用户注册程序)

use.txt内容如下(注意,use.txt中预先至少有一条记录)

14071201+asdfdsafs+张三+男+14
14071202+fasdfdsaf+李四+男+14