Zacepin1. А л е к с а н д р З а це п и н
разработчик, Мобильная почта/Почта
a l e x a n d e r. z a t s e p i n @ m a i l . r u
3. 800 000
700 000
600 000
500 000
400 000
Приложения
300 000
200 000
100 000
0
2009 2010 2011 2012
10. Сокеты
Server
Client Server
Socket Socket
14. Виды возможных сетевых взаимодействий в Андроид
1. Сокеты
2. Длинные опросы (Long-polling)
3. Пуш-нотификации (Google Cloud Messaging(GCM))
4. Частые опросы сервера (Polling)
15. Виды возможных сетевых взаимодействий в Андроид
1. Сокеты
2. Длинные опросы (Long-polling)
3. Пуш-нотификации (Google Cloud Messaging(GCM))
4. Частые опросы сервера (Polling)
16. Виды возможных сетевых взаимодействий в Андроид
1. Сокеты
2. Длинные опросы (Long-polling)
3. Пуш-нотификации (Google Cloud Messaging(GCM))
4. Частые опросы сервера (Polling)
18. HttpUrlConnection Server
HttpContext
HttpRequest
HttpEntity
HttpClient
Server
HttpResponse
HttpEntity
20. HttpUrlConnection connection = null;
try {
URL url = new URL("http://example.com");
connection = (HttpUrlConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "text/plain");
21. HttpUrlConnection connection = null;
try {
URL url = new URL("http://example.com");
connection = (HttpUrlConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "text/plain");
connection.connect();
22. HttpUrlConnection connection = null;
try {
URL url = new URL("http://example.com");
connection = (HttpUrlConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "text/plain");
connection.connect();
int statusCode = connection.getResponseCode();
...
23. HttpUrlConnection connection = null;
try {
URL url = new URL("http://example.com");
connection = (HttpUrlConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "text/plain");
connection.connect();
int statusCode = connection.getResponseCode();
...
readTextFromServer();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
}
24. try {
HttpGet request = new HttpGet("http://example.com");
25. try {
HttpGet request = new HttpGet("http://example.com");
request.setHeader("Accept", "text/plain");
26. try {
HttpGet request = new HttpGet("http://example.com");
request.setHeader("Accept", "text/plain");
HttpResponse response = getHttpClient().execute(request);
27. try {
HttpGet request = new HttpGet("http://example.com");
request.setHeader("Accept", "text/plain");
HttpResponse response = getHttpClient().execute(request);
int statusCode = response.getStatusLine().getStatusCode();
...
28. try {
HttpGet request = new HttpGet("http://example.com");
request.setHeader("Accept", "text/plain");
HttpResponse response = getHttpClient().execute(request);
int statusCode = response.getStatusLine().getStatusCode();
...
return EntityUtils.toString(response.getEntity());
} catch (Exception e) {
e.printStackTrace();
}
29. HttpUrlConnection Server
HttpContext
HttpRequest
HttpEntity
HttpClient
Server
HttpResponse
HttpEntity
31. HttpUrlConnection
HttpUrlConnection
Server
…
HttpUrlConnection
App
HttpContext
HttpRequest
HttpEntity
HttpClient
Server
HttpResponse
HttpEntity
App
35. Потокобезопасность
HttpClient
1
2 ThreadSafeClientConnManager
Thread N
1
connection 1
... connection N
2
connection 2
37. Потокобезопасность
static {
...
HttpParams params = new BasicHttpParams();
ConnManagerParams.setMaxTotalConnections(params, 10);
ConnManagerParams.setMaxConnectionsPerRoute(params,
new ConnPerRoute() {
@Override
public int getMaxForRoute(HttpRoute route) {
return 5;
}
});
38. Потокобезопасность
static {
...
HttpParams params = new BasicHttpParams();
ConnManagerParams.setMaxTotalConnections(params, 10);
ConnManagerParams.setMaxConnectionsPerRoute(params,
new ConnPerRoute() {
@Override
public int getMaxForRoute(HttpRoute route) {
return 5;
}
});
ThreadSafeClientConnManager cm =
new ThreadSafeClientConnManager(params, schemeRegistry);
}
39. Потокобезопасность
static {
...
HttpParams params = new BasicHttpParams();
ConnManagerParams.setMaxTotalConnections(params, 10);
ConnManagerParams.setMaxConnectionsPerRoute(params,
new ConnPerRoute() {
@Override
public int getMaxForRoute(HttpRoute route) {
return 5;
}
});
ThreadSafeClientConnManager cm =
new ThreadSafeClientConnManager(params, schemeRegistry);
httpClient = new DefaultHttpClient(cm, params);
}
46. Номер Время(ms)
запроса KeepAlive = false
1 2098
2 2157
3 2037
4 2096
5 1944
6 2055
7 1865
8 2119
9 1986
10 1965
≈2032,2
47. Номер Время(ms) Время(ms)
запроса KeepAlive = false KeepAlive = true
1 2098 2023
2 2157 1604
3 2037 1698
4 2096 1774
5 1944 1173
6 2055 1573
7 1865 1683
8 2119 1670
9 1986 1666
10 1965 1541
≈2032,2 ≈1700,5
48. Номер Время(ms) Время(ms)
запроса KeepAlive = false KeepAlive = true
1 2098 2023
2 2157 1604
3 2037 1698
4 2096 1774
На 16,2% быстрее!
5 1944 1173
6 2055 1573
7 1865 1683
8 2119 1670
9 1986 1666
10 1965 1541
≈2032,2 ≈1700,5
56. Keep Alive Duration
request1
request2 TCP
request3
𝐭 App Server
𝐭𝟑> 𝐝
request4
𝐭 − 𝐭𝐢𝐦𝐞
𝐝 − 𝐤𝐞𝐞𝐩 𝐚𝐥𝐢𝐯𝐞 𝐝𝐮𝐫𝐚𝐭𝐢𝐨𝐧
57. Keep Alive Duration
request1
request2 TCP
request3
𝐭 App Server
𝐭𝟑> 𝐝
request4 TCP
𝐭 − 𝐭𝐢𝐦𝐞
𝐝 − 𝐤𝐞𝐞𝐩 𝐚𝐥𝐢𝐯𝐞 𝐝𝐮𝐫𝐚𝐭𝐢𝐨𝐧
60. Keep Alive Duration
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO){
System.setProperty("http.keepAlive", "false");
}
61. Keep Alive Duration
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO){
System.setProperty("http.keepAlive", "false");
}
Hе поддается настройке!(≈5 секунд)
62. try {
...
InputStream is = connection.getInputStream();
// Вычитывайте все данные из InputStream’a
is.close();
} catch (Exception e) {
try {
InputStream es = connection.getErrorStream();
// Вычитывайте все данные из InputStream’a
es.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
65. Гзипование траффика
...
InputStream is = response.getEntity().getContent();
Header contentEncoding =
response.getFirstHeader("Content-Encoding");
if (contentEncoding != null
&& contentEncoding.getValue().equalsIgnoreCase("gzip"))
66. Гзипование траффика
...
InputStream is = response.getEntity().getContent();
Header contentEncoding =
response.getFirstHeader("Content-Encoding");
if (contentEncoding != null
&& contentEncoding.getValue().equalsIgnoreCase("gzip")) {
is = new GZIPInputStream(is);
}
...
67. Гзипование траффика
...
InputStream is = connection.getInputStream();
String contentEncoding = connection.getContentEncoding();
if ("gzip".equalsIgnoreCase(contentEncoding)) {
is = new GZIPInputStream(connection.getInputStream());
}
...
72. Управление куками
...
CookieStore cs = getHttpClient().getCookieStore();
BasicClientCookie c = new BasicClientCookie("Mpop", cookie);
c.setDomain(".mail.ru");
cs.addCookie(c);
...
76. Установка куки в WebView
Application Browser
CookieSyncManager.createInstance(context);
WebView
WebView
77. Установка куки в WebView
Application Browser
CookieSyncManager.createInstance(context);
CookieManager.getInstance().setAcceptCookie(true);
WebView
WebView
78. Установка куки в WebView
Application Browser
CookieSyncManager.createInstance(context);
CookieManager.getInstance().setAcceptCookie(true);
CookieManager.getInstance().setCookie("mail.ru",cookie);
WebView
WebView
79. Установка куки в WebView
Application Browser
CookieSyncManager.createInstance(context);
CookieManager.getInstance().setAcceptCookie(true);
CookieManager.getInstance().setCookie("mail.ru",cookie);
WebView
//for API level >= 15
CookieManager.getInstance().setCookie(".mail.ru",cookie);
WebView
80. Установка куки в WebView
Application Browser
CookieSyncManager.createInstance(context);
CookieManager.getInstance().setAcceptCookie(true);
CookieManager.getInstance().setCookie("mail.ru",cookie);
WebView
//for API level >= 15
CookieManager.getInstance().setCookie(".mail.ru",cookie)
CookieSyncManager.getInstance().sync();
WebView
81. Установка куки в WebView
Application Browser
CookieSyncManager.createInstance(context);
CookieManager.getInstance().setAcceptCookie(true);
CookieManager.getInstance().setCookie("mail.ru",cookie);
WebView
cookie //for API level >= 15
CookieManager.getInstance().setCookie(".mail.ru",cookie)
CookieSyncManager.getInstance().sync();
WebView
cookie
82. Установка куки в WebView
Application Browser
CookieSyncManager.createInstance(context);
CookieManager.getInstance().setAcceptCookie(true);
CookieManager.getInstance().setCookie("mail.ru",cookie);
WebView
cookie //for API level >= 15
CookieManager.getInstance().setCookie(".mail.ru",cookie)
CookieSyncManager.getInstance().sync();
WebView
cookie
89. Защищенное соединение (https)
request
Application Server
Private key
Certificate
Public key
Random symmetric key
Checks certificate CA Signs certificate
90. Защищенное соединение (https)
request
Application Server
Private key
Certificate
Public key
Random symmetric key
Data transferring
Checks certificate CA Signs certificate
93. Варианты реализации https
1. KeyChain API на платформах >= 4.0
2. На платформах < 4.0 надо создавать локальное хранилище ключей
3. Доверять всем сертификатам
94. Https на платформа < 4.0
...
TrustManagerFactory tmf =
TrustManagerFactory.getInstance(algorithm);
KeyStore keyStore = KeyStore.getInstance("BKS");
InputStream in =
context.getResources().openRawResource(mykeystore);
keyStore.load(in, "mysecret".toCharArray());
in.close();
tmf.init(keyStore);
SSLContext sslc = SSLContext.getInstance("TLS");
sslc.init(null, tmf.getTrustManagers(),new SecureRandom());
...
95. Https на платформа < 4.0
private SSLSocketFactory createSslSocketFactory() {
SSLSocketFactory sf = null;
try {
KeyStore keyStore = KeyStore.getInstance("BKS");
InputStream in =
context.getResources().openRawResource(mykeystore);
keyStore.load(in, "mysecret".toCharArray());
in.close();
sf = new SSLSocketFactory(keyStore);
sf.setHostnameVerifier(STRICT_HOSTNAME_VERIFIER);
} catch (Exception e) {
e.printStackTrace();
}
return sf;
}
96. Доверять всем сертификатам
private class DummyHostnameVerifier implements HostnameVerifier{
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
97. Доверять всем сертификатам
private class DummyTrustManager implements X509TrustManager{
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
//empty
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
//empty
}
...
}
98. Полезные инструменты
1. StrictMode
2. ConnectivityManager
3. DDMS Network Traffic Tool
4. Rest-client
5. Wireshark
99. Полезные инструменты
1. StrictMode
2. ConnectivityManager
3. DDMS Network Traffic Tool
4. Rest-client
5. Wireshark
100. Полезные инструменты
1. StrictMode
2. ConnectivityManager
3. DDMS Network Traffic Tool
4. Rest-client
5. Wireshark
101. Полезные инструменты
1. StrictMode
2. ConnectivityManager
3. DDMS Network Traffic Tool
4. Rest-client
5. Wireshark
102. Полезные инструменты
1. StrictMode
2. ConnectivityManager
3. DDMS Network Traffic Tool
4. Rest-client
5. Wireshark
103. Полезные инструменты
1. StrictMode
2. ConnectivityManager
3. DDMS Network Traffic Tool
4. Rest-client
5. Wireshark
104. Полезные ссылки
1. KeyChain API – http://goo.gl/ICijf
2. Создание локального хранилища ключей – http://goo.gl/5Surx
3. Keep Alive - http://goo.gl/9cdlz
4. Минимизация расхода батареи - http://goo.gl/DML0m
5. Выполнение сетевых операций - http://goo.gl/GIVIs
106. А л е к с а н д р З а це п и н
разработчик, Мобильная почта/Почта
a l e x a n d e r. z a t s e p i n @ m a i l . r u