安卓Socket与pc端c#服务器的通信 附完整代码

7 篇文章 0 订阅
2 篇文章 0 订阅

一、前言

小生不才,学习安卓socke通信打了很多滚,遇到过很多问题,也翻过前辈们关于socket的讲解,很杂各有见解,案例也不是很完整,于是特地将此安卓Socket与pc端c#服务器的通信代码讲解与socket的资料整理一遍加深理解,希望能有所帮助,小生没写过几次博客,欢迎各位大佬提出宝贵意见。安卓客户端项目源代码与pc端C#服务器与客户端的资源已经上传:安卓Socket与pc端c#服务器的通信完整代码(包含C#服务器与安卓项目工程)-CSDN下载  https://download.csdn.net/download/zengpengqing1204/10374110

 

 

二、Socket的基本概念  

 

1、套接字(socket)概念

 

Socket(套接字)用于描述IP地址和端口,是通信链的句柄,应用程序可以通过Socket向网络发出请求或者应答网络请求。

 

Socket是支持TCP/IP协议的网络通信的基本操作单元,是对网络通信过程中端点的抽象表示,包含了进行网络通信所必需的5种信息:连接所使用的协议、本地主机的IP地址、本地进程的协议端口、远地主机的IP地址以及远地进程的协议端口。

 

套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。

 

应用层通过传输层进行数据通信时,TCP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个 TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了套接字(Socket)接口。应 用层可以和传输层通过Socket接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。

 

2 、建立socket连接

建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket ,另一个运行于服务器端,称为ServerSocket 。

套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。

服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。

客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。

连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发 给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。

 

ps:其他一些几次握手的事情我就不弄出来了,没什么太大的营养,自己了解即可,重在实战

三、Socket的使用

 1、socket的构造方法

Java在包java.net中提供了两个类Socket和ServerSocket,分别用来表示双向连接的Socket客户端和服务器端。


  Socket的构造方法如下:


  (1)Socket(InetAddress address, int port);


  (2)Socket(InetAddress address, int port, boolean stream);


  (3)Socket(String host, int port);


  (4)Socket(String host, int port, boolean stream);


  (5)Socket(SocketImpl impl);


  (6)Socket(String host, int port, InetAddress localAddr, int localPort);


  (7)Socket(InetAddress address, int port, InetAddrss localAddr, int localPort);


  ServerSocket的构造方法如下:


  (1)ServerSocket(int port);


  (2)ServerSocket(int port, int backlog);


  (3)ServerSocket(int port, int backlog, InetAddress bindAddr);

 

  其中,参数address、host和port分别是双向连接中另一方的IP地址、主机名和端口号;参数stream表示Socket是流Socket还是数据报Socket;参数localAddr和localPort表示本地主机的IP地址和端口号;SocketImpl是Socket的父类,既可以用来创建ServerSocket,也可以用来创建Socket。

 

 

2、输入流和输出流


  Socket提供了方法getInputStream()和getOutPutStream()来获得对应的输入流和输出流,以便对Socket进行读写操作,这两个方法的返回值分别是InputStream和OutPutStream对象。


  为了便于读写数据,我们可以在返回的输入输出流对象上建立过滤流,如PrintStream、InputStreamReader和OutputStreamWriter等。

 

3、关闭Socket

 

  可以通过调用Socket的close()方法来关闭Socket。在关闭Socket之前,应该先关闭与Socket有关的所有输入输出流,然后再关闭Socket。

 

 

四、安卓与PC端的socket通讯

1.主程序代码附首页链接

package com.example.android_socket_pc_zpq3;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.UnknownHostException;
 
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.EditText;
import android.widget.TextView;
import android.widget.Toast;
 
public class MainActivity extends Activity {
	private EditText ipEditText,portEditText,sendEditText;//声明输入IP编辑框,端口号编辑框,发送信息编辑框
	private TextView chatTextView;//声明聊天记录显示文本
	private Thread connectThread;//声明连接服务器线程
	private Handler messageHandler;//声明信息处理机制函数
	Socket socket;//声明socket对象
	BufferedReader bufferedReader;//声明输入流对象
	OutputStream outputStream;//声明输出流对象
	Boolean isconnectBoolean = false;//初始化socket连接值为未连接
 
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		init();//初始化控件
	}
 
	//连接服务器线程:连接服务器并接收数据      本人觉得可以放一起写
	Runnable connectRunnable = new Runnable() {
 
		@Override
		public void run() {
			// TODO Auto-generated method stub
 
			try {
				//新建socket对象,填入编辑框IP,端口号
				socket=new Socket(ipEditText.getText().toString(),
						Integer.valueOf(portEditText.getText().toString()));
 
				//取得输入流、输出流
				bufferedReader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
				outputStream=socket.getOutputStream();
 
				//接收数据可用子线程也可直接在此线程操作
				char[] buffer=new char[256];//定义数组接收输入流数据
				String bufferString="";//定义一个字符接收数组数据
				int conut =0;//初始化buffer数组长度为0
				int tag=0;//初识写入数组的位置
 
				//死循环重复接收输入流数据并进行处理
				while (true) {
					//当输入流写入buffer数组的长度大于0时   即 接收到数据时
					while ((conut=bufferedReader.read(buffer))>0) {
						//将buffer数组的数据全部写入bufferString字符类型
						while ( tag<buffer.length) {
							bufferString=bufferString+buffer[tag];
							tag++;
						}
						//将数据给messageHandler刷新UI界面
						Message msgMessage =new Message();
						msgMessage.obj=bufferString;
						msgMessage.what=1;
						messageHandler.sendMessage(msgMessage);
						//初始化数据,以便处理下一条输入流信息
						tag=0;
						bufferString="";
					}
					
				}
 
 
 
			} catch (NumberFormatException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (UnknownHostException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
 
	};
 
	//初始化所有控件
	private void init() {
 
		ipEditText=(EditText) findViewById(R.id.IpeditText);
		portEditText=(EditText)findViewById(R.id.PorteditText);
		sendEditText=(EditText)findViewById(R.id.sendeditText);
 
		chatTextView=(TextView)findViewById(R.id.chattextView);
 
 
		//连接服务器按钮事件
		findViewById(R.id.connectbutton).setOnClickListener(new OnClickListener() {
 
			@Override
			public void onClick(View arg0) {
				//逻辑判断socket是否连接上,再做操作
				if (isconnectBoolean==false) {
					connectThread=new Thread(connectRunnable);
					connectThread.start();
					Toast.makeText(MainActivity.this, "连接服务器成功", 2).show();
					isconnectBoolean=true;
				}
 
 
			}
		});
 
		//断开服务器按钮事件
		findViewById(R.id.breakbutton).setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				//逻辑判断socket是否连接上,再做操作
				if (isconnectBoolean==true) {
					if (socket !=null) {
						try {
							//先关闭socket连接,再关闭输入流、输出流,
							socket.close();
							socket = null;
							bufferedReader.close();
							outputStream.close();
							
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					//中断连接线程
					connectThread.interrupt();
					Toast.makeText(MainActivity.this, "断开连接!", 2).show();
					isconnectBoolean=false;
				}
 
			}
		});
 
		//发送信息给服务器按钮事件
		findViewById(R.id.sendbutton).setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				//这里可以用线程也可以不用线程
				try {
					//输出流写入发送编辑框的信息并指定类型UTF-8,注意要加换行
					outputStream.write((sendEditText.getText().toString()+"\n").
							getBytes("utf-8"));
					//输出流发送至服务器
					outputStream.flush();
 
					//handlerMessage处理发送信息刷新UI界面
					Message msgMessage =new Message();
					msgMessage.obj=sendEditText.getText().toString();
					msgMessage.what=0;
					messageHandler.sendMessage(msgMessage);
 
				} catch (UnsupportedEncodingException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
 
 
 
			}
		});
 
		//处理接收服务器信息以及发送至服务器信息呈现聊天室效果
		messageHandler = new Handler(){
			public void handleMessage(android.os.Message msgMessage) {
				String sendString="";
				String receiveString="";
				switch (msgMessage.what) {
				case 0:
					sendString="曾鹏晴说:"+msgMessage.obj.toString()+"\n";
					chatTextView.append(sendString);
					break;
 
				case 1:
					receiveString="小权权说:"+msgMessage.obj.toString()+"\n";
					chatTextView.append(receiveString);
					break;
				default:
					break;
				}
			}
		};
 
 
 
 
	}
 
}

2、布局文件

<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" >
 
    <EditText
        android:id="@+id/IpeditText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="36dp"
        android:ems="7"
        android:text="192.168.1.101" >
 
        <requestFocus />
    </EditText>
 
    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/IpeditText"
        android:layout_alignBottom="@+id/IpeditText"
        android:layout_alignParentLeft="true"
        android:text="IP:" />
 
    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/IpeditText"
        android:layout_alignBottom="@+id/IpeditText"
        android:layout_toRightOf="@+id/IpeditText"
        android:text="Port:" />
 
    <EditText
        android:id="@+id/PorteditText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/textView2"
        android:layout_alignBottom="@+id/textView2"
        android:layout_alignParentRight="true"
        android:ems="4"
        android:text="8488" />
 
    <Button
        android:id="@+id/connectbutton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView1"
        android:layout_below="@+id/IpeditText"
        android:layout_marginTop="14dp"
        android:text="连接服务器" />
 
    <Button
        android:id="@+id/breakbutton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/connectbutton"
        android:layout_alignBottom="@+id/connectbutton"
        android:layout_marginLeft="41dp"
        android:layout_toRightOf="@+id/connectbutton"
        android:text="断开服务器" />
 
    <EditText
        android:id="@+id/sendeditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignRight="@+id/PorteditText"
        android:layout_below="@+id/connectbutton"
        android:layout_marginTop="16dp"
        android:ems="10"
        android:text="hello 小权权" />
 
    <Button
        android:id="@+id/sendbutton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/sendeditText"
        android:layout_alignRight="@+id/sendeditText"
        android:layout_below="@+id/sendeditText"
        android:layout_marginTop="14dp"
        android:text="发送信息至服务器" />
 
    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/sendbutton"
        android:layout_below="@+id/sendbutton"
        android:layout_marginTop="14dp"
        android:text="聊天记录:" />
 
    <TextView
        android:id="@+id/chattextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textView3"
        android:layout_toRightOf="@+id/textView1"
        android:text="" />
 
</RelativeLayout>

3、PC端c#服务器代码附首页链接

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
 
using System.Net.Sockets;
using System.Net;
using System.Threading;
 
namespace socket
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        Socket ServerSocket = null;
 
        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            IPEndPoint IPE = new IPEndPoint(IPAddress.Parse(tboxIP.Text), Int32.Parse(tboxPort.Text));
            ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            ServerSocket.Bind(IPE);
            ServerSocket.Listen(10);
            showmsg("服务器已启动,监听中...");
 
            Thread thread = new Thread(ListenClientConnect);
            thread.IsBackground=true;
            thread.Start();
 
        }
        Dictionary<string, Socket> dic = new Dictionary<string, Socket>();
        private void ListenClientConnect(object obj)
        {
            while (true)
            {
                Socket socketClient = ServerSocket.Accept() ;
                string RemoteIP = socketClient.RemoteEndPoint.ToString();
                dic.Add(RemoteIP, socketClient);
                Dispatcher.Invoke(()=>lstboxIP.Items.Add(RemoteIP));
                showmsg(RemoteIP + "已连接");
 
                Thread recieveThread = new Thread(recievemsg);
                recieveThread.IsBackground = true;
                recieveThread.Start(socketClient);
            }
        }
 
        private void recievemsg(object soc)
        {
            Socket socketClient = (Socket)soc;
            while (true)
            {
                byte[] buffer = new byte[1024];
                int n = socketClient.Receive(buffer);
                //string msg = Encoding.Default.GetString(buffer, 0, n);
                string msg = Encoding.UTF8.GetString(buffer, 0, n);
                //可在这里指定接受数据格式
 
                showmsg(socketClient.RemoteEndPoint.ToString()+":"+msg);
            }
        }
 
        private void showmsg(string p)
        {
            Dispatcher.BeginInvoke(new Action(() =>
                {
                    rtbx.AppendText(p + "\r\n");
                }));
        }
 
        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            ServerSocket.Close();
        }
 
        private void btnSend_Click(object sender, RoutedEventArgs e)
        {
            showmsg(tboxMsg.Text);
            string ip = lstboxIP.SelectedValue.ToString();
            //byte[] by = Encoding.UTF8.GetBytes(tboxMsg.Text);
            byte[] by = Encoding.Default.GetBytes(tboxMsg.Text);
            dic[ip].Send(by,0);
            tboxMsg.Text = "";
        }
    }
}

4、布局文件

<Window x:Class="socket.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Label x:Name="label" Content="IP地址:" HorizontalAlignment="Left" Margin="24,15,0,0" VerticalAlignment="Top"/>
        <TextBox x:Name="tboxIP" HorizontalAlignment="Left" Height="23" Margin="86,17,0,0" TextWrapping="Wrap" Text="192.168.1.101" VerticalAlignment="Top" Width="92"/>
        <Label x:Name="label1" Content="端口:" HorizontalAlignment="Left" Margin="183,16,0,0" VerticalAlignment="Top"/>
        <TextBox x:Name="tboxPort" HorizontalAlignment="Left" Height="23" Margin="228,17,0,0" TextWrapping="Wrap" Text="8488" VerticalAlignment="Top" Width="43"/>
        <Button x:Name="btnStart" Content="服务器启动" HorizontalAlignment="Left" Margin="287,19,0,0" VerticalAlignment="Top" Width="75" Click="btnStart_Click"/>
        <Button x:Name="btnStop" Content="服务器停止" HorizontalAlignment="Left" Margin="377,19,0,0" VerticalAlignment="Top" Width="75" Click="btnStop_Click"/>
        <ListBox x:Name="lstboxIP" HorizontalAlignment="Left" Height="180" Margin="377,65,0,0" VerticalAlignment="Top" Width="116"/>
        <Button x:Name="btnSend" Content="发送信息" HorizontalAlignment="Left" Margin="377,271,0,0" VerticalAlignment="Top" Width="75" Click="btnSend_Click"/>
        
        <TextBox x:Name="tboxMsg" HorizontalAlignment="Left" Height="23" Margin="24,270,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="320"/>
        <RichTextBox x:Name="rtbx" HorizontalAlignment="Left" Height="180" Margin="24,65,0,0" VerticalAlignment="Top" Width="320">
            <FlowDocument>
                <Paragraph>
                </Paragraph>
            </FlowDocument>
        </RichTextBox>
 
    </Grid>
</Window>

 

5、聊天室效果图

原文地址:https://blog.csdn.net/Zengpengqing1204/article/details/80083651

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值