自己动手编写仿QQ的app -1注册界面by sdust iot zhl

协议:tcp/ip 协议
架构:c/s 架构
数据库:mysql
服务器端接口语言 :python
客户端语言:安卓

注册:服务器端创建套接字,获取客户端发来的json数据,解析完后存入数据库

首先安装服务器端mysql 数据库 ,这里我直接安装了 phpstudy
然后 进入cmd,mysql - u root - p 输入密码登录数据库
然后进入 test 数据库
创建如下的数据表

mysql> create table users (
    ->  `id` int not null auto_increment ,
    -> `account` char(10) not null,
    -> `password` char(10) not null,
    ->  primary key (`id`),
    -> unique key( `account`)
    -> );

即创建了一个 主键为id 拥有两个栏目,account (账户)与password(密码)的表用于储存用户账户密码,并且设置各栏目非空,主键自增,account(账户)键值唯一,即用户名唯一

然后开始编写服务器端代码

#coding:utf-8
import MySQLdb ,socket,threading ,time,json
from json import *


class myThread (threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        print "Starting " + self.name

        try:
            data=conn.recv(1024)
            print data
            dict=json.loads(data)
            dict = eval(dict)
            threadLock.acquire()
            cur=conne.cursor()
            account=dict['account']
            password = dict['password']
            tuple = (account,password)
            sql = " INSERT INTO users (account,password) VALUES(%s,%s)";
            cur.execute(sql,tuple)
            conn.send("写入成功")
            cur.close()
            print("succeed in writing")
            threadLock.release()
        finally:
            conn.close()

conne=MySQLdb.connect(host='127.0.0.1',user='root',passwd='ONS2015',db='test',port=3306)

threadLock = threading.Lock()
HOST='127.0.0.1'
PORT=2333
s= socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind(('127.0.0.1',2333))
s.listen(5)
while (1):
    conn,addr = s.accept()
    print'Connected by',addr
    # 接受客户端端的连接后,就开启一个线程处理客户端的数据
    thread = myThread()
    thread.start()

其中

dict=json.loads(data)
dict = eval(dict)
是将json数据流转化为string,再转化为dict ,从而接下来对其进行操作

而conne=MySQLdb.connect(host=’127.0.0.1’,user=’root’,passwd=’ONS2015’,db=’test’,port=3306)
是数据库连接操作

sql = ” INSERT INTO users (account,password) VALUES(%s,%s)”;
cur.execute(sql,tuple)
则是向数据库中插入数据的操作

客户端先使用 python 进行简单测试,代码如下:

import MySQLdb ,socket,threading ,time,json
from json import *

HOST='127.0.0.1'
PORT=2333
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('127.0.0.1',2333))
dict="{'account':'doge','password':'123'}"
d=json.dumps(dict)
s.sendall(d)
data=s.recv(1024)
print data

主要使用了d=json.dumps(dict)将dict转化为json字符串

服务器端输出如下:

C:\Python27\python.exe E:/代码文件/python/client_test.py
Connected by ('127.0.0.1', 59171)
Starting Thread-1
"{'account':'doge','password':'123'}"
succeed in writing

客户端如下:

C:\Python27\python.exe E:/代码文件/python/client.py
写入成功

Process finished with exit code 0

接下来开始写安卓端的界面,这是第一次做出来的效果图

其中UI,即xml文件上遇到的问题如下:
1.密码输入只以 * 显示

android:inputType="textPassword"

2.设置一个隐藏的提示功能的文本

android:hint="请输入账户"

3.限制输入只能为字母数字下划线
以及长度限制最高为10
android:digits="1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM_"
android:maxLength="10"

4.设置隐藏的提示框,即设置一个字体颜色,内容为空的textview ,用于在接下来提示输入

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#f4f4f3"
    android:orientation="vertical">
<ImageView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:contentDescription="dp"
    android:src="@mipmap/dp"
    android:layout_weight="0.15"/>
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="0.05"
        android:orientation="horizontal"

        >
        <TextView
            android:layout_width="0sp"
            android:layout_height="match_parent"
            android:text="账户"
            android:id="@+id/register_tv1"
            android:layout_weight="0.02"
            android:gravity="center"
            android:textSize="20sp"
            />
        <EditText
            android:layout_width="0sp"
            android:layout_height="match_parent"
            android:hint="请输入账户"
            android:id="@+id/register_account"
            android:layout_weight="0.07"
            android:digits="1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM_"
            android:maxLength="10"
            />

    </LinearLayout>
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/register_warm1"
        android:text=""
        android:layout_weight="0.0005"
        android:gravity="center"
        android:textSize="20sp"
        android:textColor="#fc4984"
        android:visibility="visible"
        />
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="0.05"
        android:orientation="horizontal"
        >
        <TextView
            android:layout_width="0sp"
            android:layout_height="match_parent"
            android:text="密码"
            android:id="@+id/register_tv2"
            android:layout_weight="0.02"
            android:gravity="center"
            android:textSize="20sp"
            />
        <EditText
            android:layout_width="0sp"
            android:layout_height="match_parent"
            android:hint="请输入密码"
            android:id="@+id/register_password1"
            android:layout_weight="0.07"
            android:inputType="textPassword"
            android:digits="1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM_"
            android:maxLength="10"
            />


    </LinearLayout>
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text=""
        android:id="@+id/register_warm2"
        android:layout_weight="0.0005"
        android:gravity="center"
        android:textSize="20sp"
        android:textColor="#fc4984"
        android:visibility="visible"
        />
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="0.05"
        android:orientation="horizontal"
        >
        <TextView
            android:layout_width="0sp"
            android:layout_height="match_parent"
            android:text="密码"
            android:id="@+id/register_tv3"
            android:layout_weight="0.02"
            android:gravity="center"
            android:textSize="20sp"
            />
        <EditText
            android:layout_width="0sp"
            android:layout_height="match_parent"
            android:hint="请再次输入密码"
            android:id="@+id/register_password2"
            android:layout_weight="0.07"
            android:inputType="textPassword"
            android:digits="1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM_"
            android:maxLength="10"
            />


    </LinearLayout>
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text=""
        android:id="@+id/register_warm3"
        android:layout_weight="0.0005"
        android:gravity="center"
        android:textSize="20sp"
        android:textColor="#fc4984"
        android:visibility="visible"
        />
    <LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:layout_weight="0.05"
    android:orientation="horizontal"
    >

        <TextView
            android:layout_width="0sp"
            android:layout_height="wrap_content"
            android:text="性别"
            android:textSize="20sp"
            android:gravity="center"
            android:layout_weight="0.29"/>
    <RadioGroup
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="0.7">
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="男"
            android:layout_weight="0.5"/>

            <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="女"
            android:layout_weight="0.5"/>
        </LinearLayout>
    </RadioGroup>
</LinearLayout>
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="0.1"
        android:orientation="horizontal"
        >
    <Button
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:text="完成注册"
    android:id="@+id/register_bt"
    android:layout_weight="0.005"
    android:background="#1fb2f6"
    android:textColor="#fefefe"
    android:textSize="20sp"
        />
    </LinearLayout>


</LinearLayout>

从中获得了很多学习经验,
如:控件可以嵌套LinearLayout,从而形成各种风格的布局
字体大小要设置为sp单位
可以设置RadioGroup 管理RadioButton

这是最终的客户端代码

package doge.dp.test;

import android.os.Bundle;
import android.os.Looper;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.NavigationView;
import android.support.design.widget.Snackbar;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;


public class MainActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.setDrawerListener(toggle);
        toggle.syncState();

        NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(this);
        SetListener();
    }

    @Override
    public void onBackPressed() {
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @SuppressWarnings("StatementWithEmptyBody")
    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        // Handle navigation view item clicks here.
        int id = item.getItemId();

        if (id == R.id.nav_camera) {
            // Handle the camera action
        } else if (id == R.id.nav_gallery) {

        } else if (id == R.id.nav_slideshow) {

        } else if (id == R.id.nav_manage) {

        } else if (id == R.id.nav_share) {

        } else if (id == R.id.nav_send) {

        }

        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        drawer.closeDrawer(GravityCompat.START);
        return true;
    }
    //注册按钮响应事件
    public void SetListener()
    {
        //定义控件变量
        final  EditText register_account = (EditText) findViewById(R.id.register_account);
        final  EditText register_password1 = (EditText) findViewById(R.id.register_password1);
        final  EditText register_password2 = (EditText) findViewById(R.id.register_password2);
        final  TextView register_warm1     = (TextView) findViewById(R.id.register_warm1);
        final TextView register_warm2     = (TextView) findViewById(R.id.register_warm2);
        final TextView register_warm3     = (TextView) findViewById(R.id.register_warm3);
        //设置按钮点击监听
        Button   register_bt        = (Button) findViewById(R.id.register_bt);




        TextWatcher textWatcher1 = new TextWatcher() {
            public void onTextChanged(CharSequence s, int start, int before,
                                      int count) {
            }
            public void beforeTextChanged(CharSequence s, int start, int count,
                                          int after) {
            }
            public void afterTextChanged(Editable s) {
                String register_account_text = register_account.getText().toString();
                if(s.length()<6||s.length()>10)
                {
                    register_warm1.setText("请将账号长度控制在6-10位之间");
                }
                else
                    register_warm1.setText("");
            }
        };
        register_account.addTextChangedListener(textWatcher1);


        TextWatcher textWatcher2 = new TextWatcher() {
            public void onTextChanged(CharSequence s, int start, int before,
                                      int count) {
            }
            public void beforeTextChanged(CharSequence s, int start, int count,
                                          int after) {
            }
            public void afterTextChanged(Editable s) {
                String register_password1_text = register_password1.getText().toString();
                String register_password2_text = register_password2.getText().toString();
                if(register_password1_text.length()<6||register_password1_text.length()>10)
                {
                    register_warm2.setText("请将密码长度控制在6-10位之间");
                }
                else
                    register_warm2.setText("");
                if(!register_password2_text.equals(register_password1_text))
                    register_warm3.setText("请输入一样的密码");
                else
                    register_warm3.setText("");


            }
        };
        register_password1.addTextChangedListener(textWatcher2);



        TextWatcher textWatcher3 = new TextWatcher() {
            public void onTextChanged(CharSequence s, int start, int before,
                                      int count) {
            }
            public void beforeTextChanged(CharSequence s, int start, int count,
                                          int after) {
            }
            public void afterTextChanged(Editable s) {
                String register_password2_text = register_password2.getText().toString();
                String register_password1_text = register_password1.getText().toString();
                if(!register_password2_text.equals(register_password1_text))
                {
                    register_warm3.setText("请输入一样的密码");
                }
                else
                    register_warm3.setText("");
            }
        };
        register_password2.addTextChangedListener(textWatcher3);


        Button   reister_bt        = (Button) findViewById(R.id.register_bt);
        reister_bt.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View view) {
                String register_password1_text = register_password1.getText().toString();
                String register_password2_text = register_password2.getText().toString();
                String register_account_text = register_account.getText().toString();
                String register_warm1_text = register_warm1.getText().toString();
                String register_warm2_text = register_warm2.getText().toString();
                String register_warm3_text = register_warm3.getText().toString();
                if ( register_password1_text.equals("")||register_password2_text.equals("")||register_account_text.equals("") )
                    Toast.makeText( getApplicationContext(),"请输入完整注册信息",Toast.LENGTH_SHORT).show();
                else if (!register_warm1_text.equals("")||!register_warm2_text.equals("")||!register_warm3_text.equals(""))
                    Toast.makeText( getApplicationContext(),"请输入正确的注册信息",Toast.LENGTH_SHORT).show();
                else
                {
                    Toast.makeText(getApplicationContext(),"flag",Toast.LENGTH_LONG);


                    ExecutorService exec = Executors.newCachedThreadPool();
                    MyTask task = new MyTask();
                    Future<Boolean> future = exec.submit(task);
                    try {

                        future.get(1, TimeUnit.SECONDS);
                    } catch (InterruptedException e) {
                        Toast.makeText(getApplicationContext(),"请求超时,请检查网络",Toast.LENGTH_LONG).show();

                    } catch (ExecutionException e) {
                        Toast.makeText(getApplicationContext(),"请求超时,请检查网络",Toast.LENGTH_LONG).show();

                    } catch (TimeoutException e) {
                        Toast.makeText(getApplicationContext(),"请求超时,请检查网络",Toast.LENGTH_LONG).show();

                    }
                    finally {
                        exec.shutdownNow();
                    }

                }

            }
        });
    }


    //继承了callable接口
    class MyTask implements Callable<Boolean> {
        String flag="0";
        @Override
        public Boolean call() throws Exception {

            try
            {
                getMainLooper().prepare();
                EditText register_account = (EditText) findViewById(R.id.register_account);
                EditText register_password1 = (EditText) findViewById(R.id.register_password1);
                EditText register_password2 = (EditText) findViewById(R.id.register_password2);
                String account =  register_account.getText().toString();
                String password =  register_password1.getText().toString();
                Socket socket = new Socket("10.0.2.2", 2333);
                OutputStream outputStream = socket.getOutputStream();
                String jsonStr = "{\"account\": \""+ account +"\"," + " \"password\": \""+password+"\"}";
                BufferedWriter BW = new BufferedWriter(new OutputStreamWriter(outputStream));
                BW.write(jsonStr);
                BW.flush();
                InputStream is=socket.getInputStream();
                BufferedReader br=new BufferedReader(new InputStreamReader(is));
                int data  =br.read();
                System.out.println(data);
                if(data==49)
                    Toast.makeText(getApplicationContext(),"注册成功",Toast.LENGTH_LONG).show();
                else
                    Toast.makeText(getApplicationContext(),"已存在同名账户,请更换账户名",Toast.LENGTH_LONG).show();
                socket.close();

                flag="1";
                getMainLooper().loop();

            }
            catch (java.net.SocketTimeoutException e)
            {
                Toast.makeText(getApplicationContext(),"连接失败,请检查网络",Toast.LENGTH_LONG).show();
            }
            catch (IOException e) {
                Toast.makeText(getApplicationContext(), "连接失败,请检查网络", Toast.LENGTH_LONG).show();
                e.printStackTrace();
            }


            return true;

        }
    }



}

这是最终的修改过后的服务器端代码

#coding:utf-8
import MySQLdb ,socket,threading ,time,json
from json import *


class myThread (threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    #线程的主体代码
    def run(self):
        print "Starting " + self.name

        try:
            data=conn.recv(1024)   #接受数据
            dict = eval(data)     #强转为dict
            account=dict['account']
            password = dict['password']
            tuple = (account,password)
            sql = " INSERT INTO users (account,password) VALUES(%s,%s)";
            threadLock.acquire()    #获取线程锁
            #接下来执行数据库操作
            cur=conne.cursor()
            cur.execute(sql,tuple)
            #执行完毕后向客户端发1表示成功
            conn.send("1")
            print("succeed in writing")
        except Exception,ex:
            conn.send("0")
            print("failed in writing")
        finally:
            cur.close()
            threadLock.release()
            conn.close()
#连接数据库
conne=MySQLdb.connect(host='127.0.0.1',user='root',passwd='ONS2015',db='test',port=3306)
threadLock = threading.Lock()
HOST='127.0.0.1'
PORT=2333
#创建socket
s= socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind(('127.0.0.1',2333))
#设置最高同时监听数
s.listen(1000)
while (1):
    conn,addr = s.accept()
    # 接受客户端端的连接后,就开启一个线程处理客户端的数据
    thread = myThread()
    thread.start()

这是最终效果图:
1.未填完整信息
未填完整信息

2.输入信息不正确
输入信息不正确

3.网络连接超时
网络连接超时

4存在相同用户名.
存在相同用户名

5,注册成功
注册成功

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值