就用一个实例说明Socket是如何使用TCP的

来源:互联网 发布:php无限极分类图片 编辑:程序博客网 时间:2024/06/01 09:25

基础简介


Android与服务器的通信方式主要有两种方式
Http通信
Socket通信

Http通信
就是一问一答的形式,只有客户端发起访问,服务端才响应,并且属于短连接,响应完成即断开连接。
Socket通信是在双方建立起连接后就可以直接进行数据的交换传输,最大的特点是在连接时可实现信息的主动推送,而不需要每次由客户端向服务器发送请求这么被动。


端口通信
Socket又称套接字,在程序内部提供了与外界通信的端口,即端口通信。

通过建立socket连接,可为通信双方的数据传输传提供通道。
socket的主要特点 数据丢失率低,使用简单且易于移植。

我们在传输数据时,可以只使用(传输层)TCP/IP协议,但是那样的话,如果没有应用层,便无法识别数据内容,如果想要使传输的数据有意义,则必须使用到应用层协议,应用层协议有很多,比如HTTP、FTP、TELNET等,也可以自己定义应用层协议。WEB使用HTTP协议作应用层协议,以封装HTTP文本信息,然后使用TCP/IP做传输层协议将它发到网络上。
 Socket是一个针对TCP和UDP编程的接口,你可以借助它建立TCP连接等等。而TCP和UDP协议属于传输层 。
  而http是个应用层的协议,它实际上也建立在TCP协议之上。 
  CSDN博文中曾这样描述两者的关系:
  HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力

Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。Socket的出现只是使得程序员更方便地使用TCP/IP协议栈而已,是对TCP/IP协议的抽象,从而形成了我们知道的一些最基本的函数接口。


1 . TCP是面向链接的,虽然说网络的不安全不稳定特性决定了多少次握手都不能保证连接的可靠性,但TCP的三次握手在最低限度上(实际上也很大程度上保证了)保证了连接的可靠性;而UDP不是面向连接的,UDP传送数据前并不与对方建立连接,对接收到的数据也不发送确认信号,发送端不知道数据是否会正确接收,当然也不用重发,所以说UDP是无连接的、不可靠的一种数据传输协议。


2 . 也正由于1所说的特点,使得UDP的开销更小数据传输速率更高,因为不必进行收发数据的确认,所以UDP的实时性更好。


知道了TCP和UDP的区别,就不难理解为何采用TCP传输协议的MSN比采用UDP的QQ传输文件慢了,但并不能说QQ的通信是不安全的,因为程序员可以手动对UDP的数据收发进行验证,比如发送方对每个数据包进行编号然后由接收方进行验证啊什么的,即使是这样,UDP因为在底层协议的封装上没有采用类似TCP的“三次握手”而实现了TCP所无法达到的传输效率。
参考:http://www.cnblogs.com/devinzhang/archive/2012/01/13/2321826.html


TCP的最基础的最脍炙人口的做人原则是:
TCP连接的三次握手
TCP断开的四次握手


实例使用

下面使用建立在TCP协议上的Socket通信案例

服务器端:

import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.PrintWriter;import java.net.ServerSocket;import java.net.Socket;public class SocketServer implements Runnable{int max=10;//最大开启线程数int i=0;  //回复数字int temp;ServerSocket serverSocket;Socket socket[];public SocketServer(){try {serverSocket=new ServerSocket(5354);//在5354端口进行侦听} catch (IOException e) {e.printStackTrace();System.out.println("can't initate ServerSocket!");return;}socket=new Socket[max];System.out.println("waiting for connect");try {while((socket[i]=serverSocket.accept())!=null){temp=i;i++;//监听到一个客户端连接进来,就开启一个工作线程new Thread(this).start();           }} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) {new SocketServer();}@Overridepublic void run() {Socket sk=socket[temp];System.out.println("accept:"+sk.getInetAddress().getHostAddress());InputStream is=null;OutputStream os=null;BufferedReader br=null;PrintWriter pw=null;try {is=sk.getInputStream();os=sk.getOutputStream();br=new BufferedReader(new InputStreamReader(is));pw=new PrintWriter(os);} catch (IOException e) {e.printStackTrace();try {sk.close();} catch (IOException e1) {e1.printStackTrace();}return;}String str;try {int m=0;//阻塞读取输入流while((str=br.readLine())!=null){System.out.println(str);pw.println(m);pw.flush();m++;}} catch (IOException e) {e.printStackTrace();}}}
其中readLine()是阻塞式监听

客户端:

建立之前千万不要忘记网络权限
<!--允许应用程序完全使用网络-->  
<uses-permission android:name="android.permission.INTERNET"/>

SocketClientActivity.java  

import android.app.Activity;import android.os.Bundle;import android.view.View;import android.widget.Button;public class SocketClientActivity extends Activity {private int count = 0;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Button button = new Button(this);//连接服务端并且监听输入流,SocketClientUT.getIns().conn("192.168.1.123");//我电脑服务端的IP//发送数据button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {count++;SocketClientUT.getIns().sendData(""+count);}});setContentView(button);}}


SocketClientUT.java

import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.PrintWriter;import java.io.Reader;import java.net.Socket;import java.net.UnknownHostException;import android.util.Log;public class SocketClientUT {private static SocketClientUT socketClientUT;private Socket socket;private PrintWriter pWriter;private BufferedReader buffReader;private String TAG = "SocketClientUT";private SocketClientUT(){//##}public static SocketClientUT getIns(){if(socketClientUT == null){socketClientUT = new SocketClientUT();}return socketClientUT;}public void conn(final String dstName){Runnable run = new Runnable() {@Overridepublic void run() {connTo(dstName);}};new Thread(run).start();}protected void connTo(String dstName) {try {Log.i(TAG ,"#socket连接中..........");socket = new Socket(dstName, 5354);} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}if(socket == null){Log.i(TAG ,"#socket连接失败");return;}Log.i(TAG ,"#socket连接成功");try {Log.i(TAG ,"#socket监听输入流");InputStream inStream = socket.getInputStream();Reader in = new InputStreamReader(inStream);buffReader = new BufferedReader(in);pWriter = new PrintWriter(socket.getOutputStream());if(buffReader == null){return;}Log.i(TAG ,"#socket输入流进入");if(pWriter == null){return;}String result ;while(true){Log.i(TAG ,"#读取中");result = buffReader.readLine();//阻塞线程if(result!=null){Log.i(TAG ,"#result="+result);}}} catch (IOException e) {e.printStackTrace();}}public void sendData(String data){pWriter.println(data);pWriter.flush();}}

其中readLine()是阻塞式监听


服务端运行如下:

waiting for connect
accept:192.168.1.123
1
2
3
4

安卓客户端:


本文来自CSDN博客,转载请注明出处 http://blog.csdn.net/dreamintheworld


0 0
原创粉丝点击