套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。
它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。
建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket ,另一个运行于服务器端,称为ServerSocket 。
套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。
1)服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。
2)客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
3)连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。
socket编程实现步骤
1)建立网络连接;
2)创建Socket;
3)打开连接到Socket的输入/输出流;
4)通过已打开的I/O流进行数据的读写操作;
5)关闭已打开的I/O流;
6)关闭Socket.
创建实体类:
package com.example.entity;
import java.io.Serializable;
public class User implements Serializable{
private String name;
private String pwd;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public User(String name, String pwd) {
super();
this.name = name;
this.pwd = pwd;
}
public User() {
super();
}
@Override
public String toString() {
return "User [name=" + name + ", pwd=" + pwd + "]";
}
}
package com.example.entity;
import java.io.Serializable;
public class MyMessage implements Serializable {
private String from;
private String to;
private String message;
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public MyMessage(String from, String to, String message) {
super();
this.from = from;
this.to = to;
this.message = message;
}
public MyMessage() {
super();
}
@Override
public String toString() {
return from + "向" + to + "发送消息为" + message;
}
}
服务器端程序
1)调用ServerSocket(int port):创建一个服务器端套接字,并绑定到指定端口上;
ServerSocket ss = new ServerSocket(8321);
2)调用accept():监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字。
Socket socket = null;
socket = ss.accept();
3)调用Socket类的getOutputStream()和getInputStream:获取输出流和输入流,开始网络数据的发送和接收。
四种常用输入流
1>对象流
InputStream is = socket.getInputStream();
// 对象流
while (true) {
Object obj=new ObjectInputStream(is).readObject();
if (obj instanceof MyMessage) {
MyMessage info = (MyMessage) obj;
System.out.println(info);
}else{
User info=(User) obj;
String name=info.getName();
String pwd=info.getPwd();
if (name.equals("aaa")&&pwd.equals("123")) {
OutputStream os=socket.getOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(os);
oos.writeObject("success");
}
System.out.println(info);
}
}
2>数据流
InputStream is = socket.getInputStream();
// 数据流
DataInputStream dis = new DataInputStream(is);
while (true) {
String info = dis.readUTF();
System.out.println(info);
}
3>字符流
InputStream is = socket.getInputStream();
// 字符流
while (true) {
InputStreamReader isr = new InputStreamReader(is, "utf-8");
char[] cha = new char[1024 * 4];
int len = isr.read(cha);
if (len > 0) {
System.out.println(new String(cha, 0, len));
}
}
4>字节流
InputStream is = socket.getInputStream();
// 字节流
while (true) {
byte[] bt = new byte[1024];
while (is.read(bt) != -1) {
System.out.println(new String(bt, "utf-8"));
}
}
4)最后关闭通信套接字。
客户端程序
1)调用Socket():创建一个流套接字,并连接到服务器端;
2)调用Socket类的getOutputStream()和getInputStream:获取输出流和输入流,开始网络数据的发送和接收。
四种常用输入流
1>对象流
OutputStream os = socket.getOutputStream();
//对象流
MyMessage myMessage=new MyMessage(socket.getInetAddress().toString(), "服务器", msg);
ObjectOutputStream oos=new ObjectOutputStream(os);
oos.writeObject(myMessage);
2>数据流
OutputStream os = socket.getOutputStream();
//数据流
DataOutputStream dos = new DataOutputStream(os);
dos.writeUTF(msg);
3>字符流
OutputStream os = socket.getOutputStream();
//字符流
OutputStreamWriter osw=new OutputStreamWriter(os);
osw.write(msg);
osw.flush();
4>字节流
OutputStream os = socket.getOutputStream();
//字节流
byte[] buffer=msg.getBytes("utf-8");
os.write(buffer);
3)最后关闭通信套接字。
整体代码:
1)实体类
package com.example.entity;
import java.io.Serializable;
public class User implements Serializable{
private String name;
private String pwd;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public User(String name, String pwd) {
super();
this.name = name;
this.pwd = pwd;
}
public User() {
super();
}
@Override
public String toString() {
return "User [name=" + name + ", pwd=" + pwd + "]";
}
}
package com.example.entity;
import java.io.Serializable;
public class MyMessage implements Serializable {
private String from;
private String to;
private String message;
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public MyMessage(String from, String to, String message) {
super();
this.from = from;
this.to = to;
this.message = message;
}
public MyMessage() {
super();
}
@Override
public String toString() {
return from + "向" + to + "发送消息为" + message;
}
}
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import com.example.entity.MyMessage;
import com.example.entity.User;
public class MyServerSocket {
public static void main(String[] args) {
Socket socket = null;
ServerSocket ss = null;
try {
ss = new ServerSocket(8321);
System.out.println("服务器启动...");
while (true) {
socket = ss.accept();
System.out.println("有客户端进来...");
String ip = socket.getInetAddress().toString();
int port = socket.getPort();
System.out.println("连接进来的客户ip是" + ip + "端口是" + port);
new Thread(new waitThread(socket)).start();
}
} catch (IOException e) {
System.out.println("通信失败");
}
}
}
class waitThread implements Runnable {
Socket socket = null;
public waitThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
InputStream is = socket.getInputStream();
// 对象流
while (true) {
Object obj=new ObjectInputStream(is).readObject();
if (obj instanceof MyMessage) {
MyMessage info = (MyMessage) obj;
System.out.println(info);
}else{
User info=(User) obj;
String name=info.getName();
String pwd=info.getPwd();
if (name.equals("aaa")&&pwd.equals("123")) {
OutputStream os=socket.getOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(os);
oos.writeObject("success");
}
System.out.println(info);
}
}
/*// 数据流
DataInputStream dis = new DataInputStream(is);
while (true) {
String info = dis.readUTF();
System.out.println(info);
}*/
/*// 字符流
while (true) {
InputStreamReader isr = new InputStreamReader(is, "utf-8");
char[] cha = new char[1024 * 4];
int len = isr.read(cha);
if (len > 0) {
System.out.println(new String(cha, 0, len));
}
}*/
/*// 字节流
while (true) {
byte[] bt = new byte[1024];
while (is.read(bt) != -1) {
System.out.println(new String(bt, "utf-8"));
}
}*/
} catch (Exception e){
e.printStackTrace();
}
}
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/main_connection"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="连接服务端" />
<EditText
android:id="@+id/main_et"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="请输入消息"/>
<Button
android:id="@+id/main_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送" />
<EditText
android:id="@+id/main_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="请输入姓名"/>
<EditText
android:id="@+id/main_pwd"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="请输入密码"/>
<Button
android:id="@+id/main_login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="登录"/>
</LinearLayout>
</RelativeLayout>
package com.example.socketuse;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.example.entity.MyMessage;
import com.example.entity.User;
public class MainActivity extends Activity implements OnClickListener {
private Button connectionBtn, sendBtn,loginBtn;
private EditText et,nameEt,pwdEt;
private Socket socket;
private String msg,name,pwd;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
connectionBtn = (Button) findViewById(R.id.main_connection);
sendBtn = (Button) findViewById(R.id.main_send);
loginBtn=(Button) findViewById(R.id.main_login);
et = (EditText) findViewById(R.id.main_et);
nameEt=(EditText) findViewById(R.id.main_name);
pwdEt=(EditText) findViewById(R.id.main_pwd);
connectionBtn.setOnClickListener(this);
sendBtn.setOnClickListener(this);
loginBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.main_connection:
new connectionThread().start();
break;
case R.id.main_send:
msg = et.getText().toString();
try {
OutputStream os = socket.getOutputStream();
//对象流
MyMessage myMessage=new MyMessage(socket.getInetAddress().toString(), "服务器", msg);
ObjectOutputStream oos=new ObjectOutputStream(os);
oos.writeObject(myMessage);
/*//数据流
DataOutputStream dos = new DataOutputStream(os);
dos.writeUTF(msg);*/
/*//字符流
OutputStreamWriter osw=new OutputStreamWriter(os);
osw.write(msg);
osw.flush();*/
/*//字节流
byte[] buffer=msg.getBytes("utf-8");
os.write(buffer);*/
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
case R.id.main_login:
name=nameEt.getText().toString().trim();
pwd=pwdEt.getText().toString().trim();
try {
OutputStream os = socket.getOutputStream();
User user=new User(name, pwd);
ObjectOutputStream oos=new ObjectOutputStream(os);
oos.writeObject(user);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Thread(new ReadThread()).start();
default:
break;
}
}
public class connectionThread extends Thread {
@Override
public void run() {
try {
socket = new Socket("192.169.41.225", 8321);
Message message=Message.obtain();
message.arg1=1;
handler.sendMessage(message);
} catch (Exception e) {
Message message=Message.obtain();
message.arg1=2;
handler.sendMessage(message);
}
}
}
class ReadThread implements Runnable{
@Override
public void run() {
try {
InputStream is=socket.getInputStream();
while (true) {
ObjectInputStream ois=new ObjectInputStream(is);
String info=(String) ois.readObject();
Message message=Message.obtain();
message.arg1=3;
message.obj=info;
handler.sendMessage(message);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Handler handler=new Handler(){
public void handleMessage(Message msg) {
if (msg.arg1==1) {
Toast.makeText(MainActivity.this, "服务器连接成功", Toast.LENGTH_SHORT).show();
}else if (msg.arg1==2) {
Toast.makeText(MainActivity.this, "服务器连接失败", Toast.LENGTH_SHORT).show();
}else if (msg.arg1==3) {
Toast.makeText(MainActivity.this, msg.obj.toString(), Toast.LENGTH_SHORT).show();
}
};
};
}
注意:服务器和客户端的实体类要相同的包名和类名。
效果: