网游开发之socket的简单设计

对于普通应用的网络模块一般使用http文本协议,在android开发中使用http协议比较简单,sdk已经做了很好的封装了,具体使用方法可以参考我的这篇博文。而在游戏开发中,可以结合使用http和socket,当然了http协议底层也是基于tcp协议的。http协议是无连接、无状态的,每次连接只能处理一个请求,然后就断了,而且发一个请求需要附加额外信息(请求行、请求头),每次请求都需要重新建立连接;使用socket的好处是更高效和省流量,建立一次连接后,只要不手动或者出现异常断开,就可以一直互相发送数据,而且是直接以字节的形式发送,不需要额外的附加信息,缺点就是难度加大了,需要服务端和客户端很好的配合,保证发送和读取时数据的顺序一致。本文通过一个简单的demo介绍开发android网游时socket的使用方法,主要包括:android客户端和一个简单的使用java实现的server端,实现客户端和服务端互相发送数据的功能。
1.客户端代码实现
首先创建一个Android应用,名称:AndroidSocketTest
然后分别创建4个文件:BytesUtil.java、BytesReader.java、BytesWriter.java、TCPCommunication.java,下面分别介绍这几个文件的用处和源码:
BytesUtil.java:包含了一些静态工具方法:基本类型和字节数组的相互转换,字符串和字节数组的相互转换,字节数组的赋值和大小重置,对输入流进行读取保存等。比较简单,下面直接看源码:


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

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

/**

author:alexzhou

email
:zhoujiangbohai@163.com

date 
:2012-11-7

 **/

 

public

final

class

BytesUtil {

 

    /**

     *整型转换成字节数组

     *
@param value 要转换的整型值

     *
@return

     */

    public

static

byte
[]
shortToBytes(
int

value) {

        byte

[]write =
new

byte
[2];

        write[0]
= (
byte)(
(value >>>
8)
&
0xFF);

        write[1]
= (
byte)(
(value >>>
0)
&
0xFF);

        return

write;

    }

 

    public

static

byte
[]
intToBytes(
int

value) {

        byte

[]write =
new

byte
[4];

        write[0]
= (
byte)(
(value >>>
24)
&
0xFF);

        write[1]
= (
byte)(
(value >>>
16)
&
0xFF);

        write[2]
= (
byte)(
(value >>>
8)
&
0xFF);

        write[3]
= (
byte)(
(value >>>
0)
&
0xFF);

        return

write;

    }

 

    public

static

byte
[]
longToBytes(
long

value) {

        byte

[]write =
new

byte
[8];

        write[0]
= (
byte)(
(value >>>
56)
&
0xFF);

        write[1]
= (
byte)(
(value >>>
48)
&
0xFF);

        write[2]
= (
byte)(
(value >>>
40)
&
0xFF);

        write[3]
= (
byte)(
(value >>>
32)
&
0xFF);

        write[4]
= (
byte)(
(value >>>
24)
&
0xFF);

        write[5]
= (
byte)(
(value >>>
16)
&
0xFF);

        write[6]
= (
byte)(
(value >>>
8)
&
0xFF);

        write[7]
= (
byte)(
(value >>>
0)
&
0xFF);

        return

write;

    }

 

    /**

     *
字节数组转换成整型

     *
@param value

     *
@return

     */

    public

static

int

bytesToInt(
byte

[]value) {

        int

i1 = (value[
0]
&
0xFF)
<<
24;

        int

i2 = (value[
1]
&
0xFF)
<<
16;

        int

i3 = (value[
2]
&
0xFF)
<<
8;

        int

i4 = (value[
3]
&
0xFF)
<<
0;

        return

(i1 | i2 | i3 | i4);

    }

 

    public

static

short

bytesToShort(
byte[]
value) {

        int

s1 = (value[
0]
&
0xFF)
<<
8;

        int

s2 = (value[
1]
&
0xFF)
<<
0;

        return

(
short)(s1
| s2);

    }

 

    public

static

long

bytesToLong(
byte[]
value) {

        long

L1 = (value[
0]
&
0xFF)
<<
56;

        long

L2 = (value[
1]
&
0xFF)
<<
48;

        long

L3 = (value[
2]
&
0xFF)
<<
40;

        long

L4 = (value[
3]
&
0xFF)
<<
32;

        long

L5 = (value[
4]
&
0xFF)
<<
24;

        long

L6 = (value[
5]
&
0xFF)
<<
16;

        long

L7 = (value[
6]
&
0xFF)
<<
8;

        long

L8 = (value[
7]
&
0xFF)
<<
0;

        return

(L1 | L2 | L3 | L4 | L5 | L6 | L7 | L8);

    }

 

    /**

     *
从指定字节数组中拷贝部分数据

     *
@param origin

     *
@param from

     *
@param to

     *
@return

     */

    public

static

byte
[]
copyBytes(
byte[]
origin,
int

from,
int

to) {

        int

len = to - from;

        if(len
<
0

|| origin.length - from <=
0)
{

            throw

new

IllegalArgumentException(
"copyBytes->error
arguments:to="
+to+",from="+from);

        }

        byte[]
ret =
new

byte
[len];

        if(len
==
0)
return

ret;

        System.arraycopy(origin,
from, ret,
0,
Math.min(len, origin.length - from));

        return

ret;

    }

 

    /**

     *
重置字节数组的大小,然后把原内容复制到新的字节数组中

     *
@param origin

     *
@param newSize

     *
@return

     */

    public

static

byte
[]
resizeBytes(
byte[]
origin,
int

newSize) {

        if(newSize
<
0)
{

            throw

new

IllegalArgumentException(
"resizeBytes->newSize
must >= 0"
);

        }

        byte[]
ret =
new

byte
[newSize];

        if(newSize
==
0)
return

ret;

        System.arraycopy(origin,0,ret,0,Math.min(origin.length,
newSize));

        return

ret;

    }

 

    /**

     *
读取输入流中字节,并保存到指定的字节数组中

     *
@param is

     *
@param data

     *
@param off

     *
@param len

     */

    public

static

void

readData(InputStream is,
byte

data[],
int

off,
int

len) {

        int

hasRead =
0;

        final

int

BUFFER =
1024;

        while(hasRead
< len) {

            try

{

                int

remain = len - hasRead;

                int

count = is.read(data, off + hasRead, remain > BUFFER ? BUFFER : remain);

                if(count
<
0)
throw

new

IOException(
"readData->read
data error"
);

                hasRead
+= count;

            }
catch

(IOException e) {

                e.printStackTrace();

            }

        }

    }

}

BytesReader.java:从服务端接收数据时使用,定义了一个字节数组类型的成员变量,用来保存从输入流中读取的数据。封装了一些从该字节数组中读取相应数据类型的函数,源码如下:


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

64

65

66

67

68

69

70

71

72

73

74

75

76

77

/**

 *
接受服务端数据时,读取字节并转换到相应类型

author:alexzhou

email
:zhoujiangbohai@163.com

date 
:2012-11-7

 **/

 

public

final

class

BytesReader {

 

    private

final

byte

[]data;

    //字节数组的大小

    private

final

int

size;

    //当前读取的位置

    private

int

position;

 

    public

BytesReader(
byte

[]data) {

        this.data
= data;

        this.size
= data.length;

        this.position
=
0;

    }

 

    public

byte
[]
read(
int

len) {

        if(len
<
0)
return

null
;

        byte[]
value = BytesUtil.copyBytes(data, position, position + len);

        this.position
+= len;

        return

value;

    }

 

    public

int

getSize() {

        return

size;

    }

 

    public

boolean

isAvailable() {

        return

size - position >
0;

    }

 

    public

short

readShort() {

        byte[]
value = read(
2);

        return

BytesUtil.bytesToShort(value);

    }

 

    public

int

readInt() {

        byte[]
value = read(
4);

        return

BytesUtil.bytesToInt(value);

    }

 

    public

long

readLong() {

        byte[]
value = read(
8);

        return

BytesUtil.bytesToLong(value);

    }

 

    public

byte

readByte() {

        int

value =
this.isAvailable()
? (
0xFF

& data[position++]) : -
1;

        return

(
byte)value;

    }

 

    public

byte
[]
readBytes() {

        int

len = readShort();

        //读取大数据

        if(len
>=
0xFFFF)
{

            len
=
this.readInt();

        }

        return

len ==
0

?
null

: read(len);

    }

 

    public

String readUTF() {

        byte[]
bytes = readBytes();

        if(null

!= bytes) {

            try

{

                return

new

String(bytes,
"UTF-8");

            }
catch

(UnsupportedEncodingException e) {

                e.printStackTrace();

            }

        }

        return

null
;

    }

}

BytesWriter.java:向服务端发送数据时使用,跟BytesReader.java对应,也是把需要发送的数据保存到字节数组中,然后一次性发送给服务器。源码如下:


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

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

/**

author:alexzhou

email
:zhoujiangbohai@163.com

date 
:2012-11-9

 **/

 

public

final

class

BytesWriter {

 

    private

byte
[]
data;

    private

int

count;

 

    public

BytesWriter() {

        this(64);

    }

 

    public

BytesWriter(
int

size) {

        this.data
=
new

byte
[size];

    }

 

    public

byte
[]
getBytes() {

        return

this
.data.length
== count ? data : count ==
0

?
null

: BytesUtil.resizeBytes(
this.data,
count);

    }

 

    public

void

write(
byte[]
value) {

        this.write(value,
0,
value ==
null

?
0

: value.length);

    }

 

    public

void

write(
byte[]
d,
int

offset,
int

len) {

        if(d
==
null

|| len ==
0)
return;

        int

newCount = count + len;

        if(newCount
>
this.data.length)
{

            int

newSize = Math.max(
this.data.length
<<
1,
newCount);

            this.data
= BytesUtil.resizeBytes(
this.data,
newSize);

        }

        System.arraycopy(d,
offset,
this.data,
this.count,
len);

        this.count
= newCount;

    }

 

    public

void

writeInt(
int

value) {

        this.write(BytesUtil.intToBytes(value));

    }

 

    public

void

writeShort(
int

value) {

        this.write(BytesUtil.shortToBytes(value));

    }

 

    public

void

writeLong(
long

value) {

        this.write(BytesUtil.longToBytes(value));

    }

 

    public

void

writeByte(
byte

value) {

        int

newCount = count +
1;

        if(newCount
>
this.data.length)
{

            int

newSize = Math.max(
this.data.length
<<
1,
newCount);

            this.data
= BytesUtil.resizeBytes(
this.data,
newSize);

        }

        this.data[count]
= value;

        this.count
= newCount;

    }

 

    public

void

writeBytes(
byte[]
value) {

        int

length = (value ==
null

?
0

: value.length);

        //发送大数据时

        if(length
>=
0xFFFF)
{

            this.writeShort(0xFFFF);

            this.writeInt(length);

        }else

{

            //告诉服务端发送的数据的大小

            this.writeShort(length);

        }

        this.write(value);

    }

 

    public

void

writeUTF(String value) {

        if(value
==
null

|| value.length() ==
0)
{

            this.writeShort(0);

        }

        byte[]
bytes =
null;

        try

{

            bytes
= value.getBytes(
"UTF-8");

        }
catch

(UnsupportedEncodingException e) {

            e.printStackTrace();

        }

        this.writeBytes(bytes);

    }

 

}

TCPCommunication.java:上面的三个类都是辅助工具类,是给它使用的,它负责socket的创建和连接服务器、读取和发送数据,以及通过Handler发送消息给UI线程更新界面显示数据。由于我们的目的是使用socket通信,所以去掉了很多代码,这里只是简单的建立一次连接,发送和接收完数据后就关闭连接了。源码如下:


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

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

public

class

TCPCommunication
implements

Runnable {

 

    private

Socket mSocket;

    private

DataInputStream mDis;

    private

DataOutputStream mDos;

    private

Handler mHandler;

 

    private

volatile

boolean

isRunning =
false;

 

    public

TCPCommunication(Handler handler) {

        this.mHandler
= handler;

    }

 

    public

boolean

isRunning() {

        return

isRunning;

    }

 

    public

void

startWork() {

        Thread
t =
new

Thread(
this);

        t.setPriority(Thread.MAX_PRIORITY);

        t.start();

    }

 

    public

void

stopWork() {

        this.isRunning
=
false;

    }

 

    @Override

    public

void

run() {

        try

{

            mSocket
=
new

Socket(
"10.0.2.2",8888);

            mDis
=
new

DataInputStream(mSocket.getInputStream());

            mDos
=
new

DataOutputStream(mSocket.getOutputStream());

            //开始发送数据到服务端

            BytesWriter
bw =
new

BytesWriter();

            String
username =
"alexzhou";

            String
password =
"123456";

            int

flag1 =
12345;

            short

flag2 =
12;

            long

flag3 = 100000000L;

            bw.writeUTF(username);

            bw.writeUTF(password);

            bw.writeInt(flag1);

            bw.writeShort(flag2);

            bw.writeLong(flag3);

            byte[]
data = bw.getBytes();

 

            BytesWriter
out =
null;

            if(data.length
>=
0xFFFF)
{

                out
=
new

BytesWriter(data.length +
6);

                out.writeShort(0xFFFF);

                out.writeInt(data.length);

            }else{

                out
=
new

BytesWriter(data.length +
2);

                out.writeShort(data.length);

            }

            out.write(data);

            mDos.write(out.getBytes());

 

            //开始从服务端接收数据

            int

len = mDis.readShort();

            if(len
==
0xFFFF)
{

                len
= mDis.readInt();

            }

            byte[]
inputData =
new

byte
[len];

            BytesUtil.readData(mDis,
inputData,
0,
len);

            BytesReader
br =
new

BytesReader(inputData);

            String
user_id = br.readUTF();

            String
recv_username = br.readUTF();

            String
nickname = br.readUTF();

            int

i = br.readInt();

            short

s = br.readShort();

            long

l = br.readLong();

 

            String
result =
"登录成功~您的信息如下\n
id:"
+user_id
+
"\n用户名:"

+ recv_username +
"\n昵称:"

+ nickname +
"\n
序列号:"

+ i +
"-"

+ s +
"-"

+ l;

            Message
msg = mHandler.obtainMessage();

            msg.what
=
0;

            msg.obj
= result;

            mHandler.sendMessage(msg);

 

            mDis.close();

            mDos.close();

            mSocket.close();

 

        }
catch

(UnknownHostException e) {

            e.printStackTrace();

        }
catch

(IOException e) {

            e.printStackTrace();

        }

    };

 

}

MainActivty.java的代码比较简单,源码:


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

public

class

MainActivity
extends

Activity {

 

    private

TextView mTextView;

    private

Button mButton;

    @Override

    public

void

onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        mTextView
= (TextView)
this.findViewById(R.id.text);

        mButton
= (Button)
this.findViewById(R.id.button_send);

        mButton.setOnClickListener(new

OnClickListener() {

 

            @Override

            public

void

onClick(View v) {

                new

TCPCommunication(mHandler).startWork();

            }

        });

    }

 

    private

Handler mHandler =
new

Handler() {

 

        @Override

        public

void

handleMessage(Message msg) {

            String
result = (String)msg.obj;

            mTextView.setText(result);

        }

 

    };

 

    @Override

    public

boolean

onCreateOptionsMenu(Menu menu) {

        getMenuInflater().inflate(R.menu.activity_main,
menu);

        return

true
;

    }

}

到此为止,Android客户端的代码已经全部完成了,记得给应用添加访问网络的权限哦:在配置文件中添加


1

<uses-permission

android:name
="android.permission.INTERNET"

/>

2.服务端代码实现
服务端的代码比较简单,当然了,一般在实际的开发中,服务端和客户端不是同一个人写的,这里我就把客户端里的那几个工具类拿来直接用了。
创建一个java项目,然后把BytesReader.java、BytesWriter.java、BytesUtil.java三个文件拷贝到项目的包下,然后创建Server.java,功能比较简单,监听8888端口,然后等待客户端连接,接收和发送数据。源码如下:


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

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

/**

author:alexzhou

email
:zhoujiangbohai@163.com

date 
:2012-11-7

 **/

 

public

final

class

Server
implements

Runnable{

 

    private

ServerSocket mServerSocket;

    private

Socket mClient;

    private

DataInputStream mDis;

    private

DataOutputStream mDos;

 

    private

boolean

isRunning =
false;

 

    public

void

start() {

        this.isRunning
=
true;

        Thread
t =
new

Thread(
this);

        t.start();

    }

 

    public

void

stop() {

        this.isRunning
=
false;

    }

 

    public

static

void

main(String []args) {

        new

Server().start();

    }

    @Override

    public

void

run() {

        try

{

            mServerSocket
=
new

ServerSocket(
8888);

            System.out.println("start
server"
);

            while(isRunning)
{

                System.out.println("wait
client connect!!"
);

                mClient
= mServerSocket.accept();

 

                //接收客户端发送的数据

                mDis
=
new

DataInputStream(mClient.getInputStream());

                //数据的长度

                int

len = mDis.readShort();

                if(len
==
0xFFFF)
{

                    len
= mDis.readInt();

                }

                System.out.println("client
data size:"

+ len);

                byte[]
inputData =
new

byte
[len];

                BytesUtil.readData(mDis,
inputData,
0,
len);

                BytesReader
br =
new

BytesReader(inputData);

                String
username = br.readUTF();

                String
password = br.readUTF();

                int

i = br.readInt();

                short

s = br.readShort();

                long

l = br.readLong();

                System.out.println("username:"+username+";password="+password+"Long="+l);

 

                //向客户端发送数据

                mDos
=
new

DataOutputStream(mClient.getOutputStream());

                BytesWriter
bw =
new

BytesWriter(
32);

                String
user_id =
"123456";

                String
nickname =
"周江海";

                bw.writeUTF(user_id);

                bw.writeUTF(username);

                bw.writeUTF(nickname);

                bw.writeInt(i);

                bw.writeShort(s);

                bw.writeLong(l);

                byte[]
data = bw.getBytes();

                BytesWriter
out =
null;

                if(data.length
>=
0xFFFF)
{

                    out
=
new

BytesWriter(data.length +
6);

                    out.writeShort(0xFFFF);

                    out.writeInt(data.length);

                }else

{

                    out
=
new

BytesWriter(data.length +
2);

                    out.writeShort(data.length);

                }

                out.write(data);

                mDos.write(out.getBytes());

 

                mDos.close();

                mDis.close();

                mClient.close();

            }

        }
catch

(IOException e) {

            e.printStackTrace();

        }  

    }

}

现在验证一下,先启动Server,然后运行Android客户端应用,屏幕中间会出现TextView和一个button,TextView的内容是HelloWorld,点击button就会发送登陆信息给服务端,然后服务端返回数据显示到TextView上。下面分别是服务端的打印消息和客户端的显示截图。


主要需要掌握基本数据类型和字符串跟字节数组的转换,然后按照指定的顺序发送。最重要的是要注意客户端和服务端从字节数组读取和往字节数组写入数据时的顺序要对应。

时间: 2024-10-25 09:15:42

网游开发之socket的简单设计的相关文章

android网游开发之socket的简单设计和实现

对于普通应用的网络模块一般使用http文本协议,在android开发中使用http协议比较简单,sdk已经做了很好的封装了,具体使用方法可以参考我的这篇博文.而在游戏开发中,可以结合使用http和socket,当然了http协议底层也是基于tcp协议的.http协议是无连接.无状态的,每次连接只能处理一个请求,然后就断了,而且发一个请求需要附加额外信息(请求行.请求头),每次请求都需要重新建立连接:使用socket的好处是更高效和省流量,建立一次连接后,只要不手动或者出现异常断开,就可以一直互相

网游开服助手怎么样?

  网游开服助手强大的抢号功能能够快速在众多游戏中抢得礼包;闹钟功能让您在第一时间获得开服信息.使用网游开服助手即可轻松下载安全绿色的手机游戏资源. 1.界面 法海不懂爱不要紧,网游开服助手很有爱,全新"复古style"界面,让你有种拥有武林秘籍的感觉. 2.搜索 全新的搜索功能,让你不用在茫茫游戏中一个一个找游戏了,输入游戏关键字,一秒钟找到你要的游戏. 3.提醒服务 提醒服务再次升级,游戏队列时间到后手机左上角会出现游戏闹钟提醒图标并配有类似手机短信的声音和震动提醒. 4.游戏升级

Android开发之CheckBox的简单使用与监听功能示例

本文实例讲述了Android开发之CheckBox的简单使用与监听功能.分享给大家供大家参考,具体如下: activity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_

Android开发之Socket通信传输简单示例

本文实例讲述了Android Socket通信传输实现方法.分享给大家供大家参考,具体如下: 1.开篇简介 Socket本质上就是Java封装了传输层上的TCP协议(注:UDP用的是DatagramSocket类).要实现Socket的传输,需要构建客户端和服务器端.另外,传输的数据可以是字符串和字节.字符串传输主要用于简单的应用,比较复杂的应用(比如Java和C++进行通信),往往需要构建自己的应用层规则(类似于应用层协议),并用字节来传输. 2.基于字符串传输的Socket案例 1)服务器端

C#开发之Socket网络编程TCP/IP层次模型、端口及报文等探讨_C#教程

1.TCP/IP层次模型 当然这里我们只讨论重要的四层 01,应用层(Application):应用层是个很广泛的概念,有一些基本相同的系统级TCP/IP应用以及应用协议,也有许多的企业应用和互联网应用.http协议在应用层运行. 02,传输层(Tanspot):传输层包括UDP和TCP,UDP几乎不对报文进行检查,而TCP提供传输保证. 03,网络层(Netwok):网络层协议由一系列协议组成,包括ICMP.IGMP.RIP.OSPF.IP(v4,v6)等. 04,链路层(Link):又称为物

iOS项目开发之Socket编程

有一段时间没有认真总结和写博客了 前段时间找工作.进入工作阶段.比较少静下来认真总结,现在静下心来总结一下最近的一些心得 前言 AsyncSocket介绍 AsyncSocket详解 AsyncSocket示例 一.前言 公司的项目用到了Socket编程,之前在学习的过程当中,用到的更多的还是http请求的方式.但是既然用到了就必须学习一下,所以就在网上找一些例子,然后想自己写一个demo.可是发现很多写iOS Socket的博客并没有很详细的说明,也可能是大神们觉得其他东西都浅显易懂. 自己专

网站开发之DIV+CSS简单布局网站入门篇(五)

        这篇文章主要介绍如何使用DIV和CSS简单布局一个网站的首页,通常将网站划分为顶部(Logo.导航条).中部(页面主要内容.左右栏目).底部(制作方介绍.超链接).这是非常基础的一篇引入性文章,采用案例的方式进行介绍的,希望对你有所帮助.运行结果如下图所示: main.html主页面代码         主要通过div进行布局的,同时<h2><a></a></h2>用户设置导航条,鼠标悬停时背景颜色切换. <html> <h

Android开发之RadioGroup的简单使用与监听示例

本文实例讲述了Android RadioGroup的简单使用与监听.分享给大家供大家参考,具体如下: activity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_pa

专访竺琦:《降龙之剑》不惧同期开测2D网游

10月27日消息,完美时空总裁竺琦近日再度出来为新游戏摇旗呐喊.与以往一样,他没有给新游戏定出在线人数的明确指标.,也不担忧同期开测的8款竞争对手产品.他自信的强调,<降龙>在题材和技术上自有优势. 26日下午,完美时空举办<降龙之剑>公测发布会,宣布游戏将于10月28日开启公测,竺琦接受了近30家媒体的群访. 被问及<降龙之剑>的营销目标,竺琦表示内部对最高在线人数没有明确指标.他还说,希望用户数不是大起大落,而希望在精耕细作下,一点一点带动项目业绩的增长. 据了解,