安卓Socket与pc端c#服务器的通信 附完整代码
一、前言
小生不才,学习安卓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、聊天室效果图



上一篇eclipse及myeclipse快捷键及各种设置 ——Eclipse的联想功能
想对作者说点什么? 我来说一句
Zengpengqing12042018-08-02 11:31:28#4楼
[java] view plain copy- 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[1024];//定义数组接收输入流数据
- //int len = bufferedReader.read(buffer);//将网络输入流的数据写入buffer数组
- int conut =0;//初始化buffer数组长度为0
- //死循环重复接收输入流数据并进行处理
- while (true) {
- //当输入流写入buffer数组的长度大于0时 即 接收到数据时
- while ((conut=bufferedReader.read(buffer))>0) {
- //将buffer数组的数据全部写入bufferString字符类型
- String bufferString = new String(buffer, 0, conut);
- //将数据给messageHandler刷新UI界面
- Message msgMessage =new Message();
- msgMessage.obj=bufferString;
- msgMessage.what=1;
- messageHandler.sendMessage(msgMessage);
- //初始化数据,以便处理下一条输入流信息
- conut=0;
- }
- }
Zengpengqing12042018-08-02 11:30:59#3楼
改了最后一个朋友反馈的问题,输入流信息的处理显示
Zengpengqing12042018-06-03 22:06:59#2楼
源代码在关闭socket时有个小修改 应该是先关闭socket,再依次关闭输入流输出流
qq_371793652018-05-27 21:48:42#1楼
博主有两把刷子哦,用上喽
更多推荐



所有评论(0)