Linux C编程--网络编程3--面向无连接的网络编程
数据报套接字操作
由于底层的协议不同,数据报套接字与数据流套接字有一些基本的不同。数据报套接字是UDP协议,UDP是无连接、不可靠的数据报协议。在这种通信方式中,客户不与服务建立连接,它只是通过sendto向服务程序发送数据报,sendto函数本身要求一个地址参数给出服务程序的地址。
同样,服务程序也不接收来自客户的连接,它只是调用recvfrom函数,这个函数等待来自某个客户的数据,并随接收到的数据报一起返回客户的地址,服务程序由此可以回应客户。
使用数据报套接字,可以将数据集中为一个包,为每个包单独地指定目的地址,并且每个包独立地进行通信。
sendto和recvfrom函数
在数据报套接字上发送和接收数据的正常方法是使用sendto和recvfrom函数。sendto向数据报套接字发送数据包,recvfrom从数据报套接字读数据包,同时报告该包从何而来。它们的原型如下:
int recvfrom(int socket, void *buffer,size_tsize,int flags,
structsockaddr *from,size_t *addrlen);
int sendto(int socket, void *buffer,size_tsize,int flags,
structsockaddr *to,size_taddrlen);
这两个函数的前3个参数socket、buffer、size与read和write的参数相同,它们分别为套接字描述符、指向读写缓冲区的指针以及读写的字节数。
说明:
recvfrom的参数from和addrlen类似于accept的最后两个参数:在函数返回时,它们给出的套接字地址结构告诉我们是谁发送的数据报。如果对这一信息不感兴趣,可指定from为一空指针,不过要注意此时参数addrlen也必须为空指针。
sendto的最后两个参数类似于connect;当发送数据报时,要在此套接字地址结构中填入协议地址以指明数据报发送给谁。
注意sendto的最后一个参数是整数值,而recvfrom的最后一个参数是指向整数的指针。
这两个函数的返回值与错误条件也与send和recv的相同,函数的返回值是实际读写的字节数。
这两个函数也可用于数据流套接字,但很少这样使用。另外,如果不必检查数据报是由谁发送的,可以使用普通的recv代替recvfrom,当不想指定flags时甚至还可用read。

上图是无连接通信的模型。
数据报通信服务器程序
最后给出TCP/IP协议族示意:
|||
先上代码:
package com.xiaogang.imageheader;import java.io.File;import android.net.Uri;import android.os.Bundle;import android.os.Environment;import android.provider.MediaStore;import android.app.Activity;import android.content.Intent;import android.graphics.Bitmap;import android.graphics.drawable.BitmapDrawable;import android.graphics.drawable.Drawable;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.ImageView;import android.widget.Toast;public class MainActivity extends Activity implements OnClickListener {private static final int IMAGE_REQUEST_CODE = 0;private static final int CAMERA_REQUEST_CODE = 1;private static final int RESIZE_REQUEST_CODE = 2;private static final String IMAGE_FILE_NAME = "header.jpg";private ImageView mImageHeader;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);setupViews();}private void setupViews() {mImageHeader = (ImageView) findViewById(R.id.image_header);final Button selectBtn1 = (Button) findViewById(R.id.btn_selectimage);final Button selectBtn2 = (Button) findViewById(R.id.btn_takephoto);selectBtn1.setOnClickListener(this);selectBtn2.setOnClickListener(this);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_selectimage:Intent galleryIntent = new Intent(Intent.ACTION_GET_CONTENT);galleryIntent.addCategory(Intent.CATEGORY_OPENABLE);galleryIntent.setType("image/*");startActivityForResult(galleryIntent, IMAGE_REQUEST_CODE);break;case R.id.btn_takephoto:if (isSdcardExisting()) {Intent cameraIntent = new Intent("android.media.action.IMAGE_CAPTURE");cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, getImageUri());cameraIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);startActivityForResult(cameraIntent, CAMERA_REQUEST_CODE);} else {Toast.makeText(v.getContext(), "请插入sd卡", Toast.LENGTH_LONG).show();}break;}}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {if (resultCode != RESULT_OK) {return;} else {switch (requestCode) {case IMAGE_REQUEST_CODE:resizeImage(data.getData());break;case CAMERA_REQUEST_CODE:if (isSdcardExisting()) {resizeImage(getImageUri());} else {Toast.makeText(MainActivity.this, "未找到存储卡,无法存储照片!",Toast.LENGTH_LONG).show();}break;case RESIZE_REQUEST_CODE:if (data != null) {showResizeImage(data);}break;}}super.onActivityResult(requestCode, resultCode, data);}private boolean isSdcardExisting() {final String state = Environment.getExternalStorageState();if (state.equals(Environment.MEDIA_MOUNTED)) {return true;} else {return false;}}public void resizeImage(Uri uri) {Intent intent = new Intent("com.android.camera.action.CROP");intent.setDataAndType(uri, "image/*");intent.putExtra("crop", "true");intent.putExtra("aspectX", 1);intent.putExtra("aspectY", 1);intent.putExtra("outputX", 150);intent.putExtra("outputY", 150);intent.putExtra("return-data", true);startActivityForResult(intent, RESIZE_REQUEST_CODE);}private void showResizeImage(Intent data) {Bundle extras = data.getExtras();if (extras != null) {Bitmap photo = extras.getParcelable("data");Drawable drawable = new BitmapDrawable(photo);mImageHeader.setImageDrawable(drawable);}}private Uri getImageUri() {return Uri.fromFile(new File(Environment.getExternalStorageDirectory(),IMAGE_FILE_NAME));}}