您的位置:首页 > 大数据 > 物联网

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

2016-08-18 20:01 465 查看
协议: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,注册成功

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: