下载地址:https://github.com/secondar/phpsocker
php部分
<?php
error_reporting(E_ALL);
set_time_limit(0);// 设置超时时间为无限,防止超时
date_default_timezone_set('Asia/shanghai');
$sk=new ws('192.168.1.85','8080');
/**
*
*/
class ws{
private $objMaster;
private $arrSockets;
private $arrUsers;
function __construct($host,$port,$linux=false){
try {
//创建服务端的socket套接流,net协议为IPv4,protocol协议为TCP
$this->objMaster = socket_create(AF_INET,SOCK_STREAM,SOL_TCP) or die("err => socket_create\n");
$strSeverName = '';
if($linux){
$strSeverName = posix_getpid();
}else{
$strSeverName = get_current_user();
}
$this->debug('info : '.date('Y-m-d H:i:s').' | '.$strSeverName.' -> socket_create');
//设置IP和端口重用,在重启服务器后能重新使用此端口;
socket_set_option($this->objMaster, SOL_SOCKET, SO_REUSEADDR, 1) or die("err => socket_set_option");
$this->debug('info : '.date('Y-m-d H:i:s').' | '.$strSeverName.' -> socket_set_option');
//绑定接收的套接流主机和端口,与客户端相对应
socket_bind($this->objMaster,$host,$port) or die("err => socket_bind");
$this->debug('info : '.date('Y-m-d H:i:s').' | '.$strSeverName.' -> socket_bind');
//监听套接流
socket_listen($this->objMaster) or die("err => socket_listen");
$this->debug('info : '.date('Y-m-d H:i:s').' | '.$strSeverName.' -> socket_listen');
}catch(\Exception $e){
$this->debug( 'info : '.date('Y-m-d H:i:s').' | '.$strSeverName.' | server listen fail -> '.socket_strerror(socket_last_error()));
}
$this->arrSockets[0] = $this->objMaster;
$this->arrUsers['server']=array('resource'=>$this->objMaster,'name'=>'sever','handshake'=>true);
$this->run();
$this->debug('info : '.date('Y-m-d H:i:s').' | '.$strSeverName.' -> run');
}
private function run(){
while (true) {
$arrChanges=$this->arrSockets;
$write=NULL;
$except=NULL;
/*
这个函数是同时接受多个连接的关键,我的理解它是为了阻塞程序继续往下执行。
socket_select ($arrSockets, $write = NULL, $except = NULL, NULL);
$arrSockets可以理解为一个数组,这个数组中存放的是文件描述符。当它有变化(就是有新消息到或者有客户端连接/断开)时,socket_select函数才会返回,继续往下执行。
$write是监听是否有客户端写数据,传入NULL是不关心是否有写变化。
$except是$arrSockets里面要被排除的元素,传入NULL是”监听”全部。
最后一个参数是超时时间
如果为0:则立即结束
如果为n>1: 则最多在n秒后结束,如遇某一个连接有新动态,则提前返回
如果为null:如遇某一个连接有新动态,则返回
*/
socket_select($arrChanges,$write,$except,NULL) or die("err => socket_select ,".socket_last_error().
socket_strerror(socket_last_error())."\n");
foreach($arrChanges as $Socket){
/*新连接到来时,被监听的端口是活跃的,如果是新数据到来或者客户端关闭链接时,活跃的是对应的客户端socket而不是服务器上被监听的端口
如果客户端发来数据没有被读走,则socket_select将会始终显示客户端是活跃状态并将其保存在readfds数组中
如果客户端先关闭了,则必须手动关闭服务器上相对应的客户端socket,否则socket_select也始终显示该客户端活跃(这个道理跟"有新连接到来然后没有用socket_access把它读出来,导致监听的端口一直活跃"是一样的)*/
//如果有新的client连接进来
if($Socket==$this->objMaster){
//接受一个socket连接
$objClient=socket_accept($this->objMaster);
//给新连接进来的socket一个唯一的ID
$key=uniqid();
$this->arrSockets[]=$objClient; //将新连接进来的socket存进连接池
$this->arrUsers[$key]=array(
'resource'=>$objClient, //记录新连接进来client的socket信息
'handshake'=>false //标志该socket资源没有完成握手
);
$this->debug('info : '.date('Y-m-d H:i:s').' | key:'.$key.' | resource:'.$objClient.' -> Connect');
}else{//否则1.为client断开socket连接,2.client发送信息
@$intLen = socket_recv($Socket, $objBuffer, 8192, 0);
$strUsers_Key=$this->search_key($Socket);
//如果接收的信息长度小于9,则该client的socket为断开连接
if($intLen<9){
//给该client的socket进行断开操作,并在$this->sockets和$this->users里面进行删除
$this->close($strUsers_Key);
continue;
}
//判断该socket是否已经握手
if(!$this->arrUsers[$strUsers_Key]['handshake']){
$this->connect($strUsers_Key,$objBuffer);
}else{
$arrMsg=$this->parse($objBuffer);
print_r(array($objBuffer));//exit();
if($arrMsg==false){
$arrMsg=json_decode($objBuffer,true);//给C#客户端用
print_r(array($arrMsg));
if($arrMsg==false){
continue;
}
}
switch ($arrMsg['type']) {
case 'login':
$arrMsg['uid']=rand(intval(time()/2),time());
$this->response_login($arrMsg,$strUsers_Key);
break;
case 'user_msg':
$arrMsg['from']=$this->arrUsers[$strUsers_Key]['name'];
$this-> broadcast($arrMsg,$arrMsg['uid'],$strUsers_Key);
break;
}
//如果不为空,则进行消息推送操作
}
}
}
}
}
/**
* [search_key 根据Socket在arrUsers里面查找相应的key]
* @param [type] $Socket [Socket]
* @return [string] [查询到的key]
*/
private function search_key($Socket){
foreach ($this->arrUsers as $k=>$v){
if($Socket==$v['resource'])
return $k;
}
return false;
}
/**
* [close 指定关闭$k对应的socket]
* @param [string] $key [socket对应的$k]
* @return [void]
*/
private function close($key){
$log='info : '.date('Y-m-d H:i:s').' | key : '.$key.' | resource : '.$this->arrUsers[$key]['resource'].' -> close';
//断开相应socket
socket_close($this->arrUsers[$key]['resource']);
//删除相应的user信息
unset($this->arrUsers[$key]);
//重新定义sockets连接池
$this->arrSockets = array();
foreach($this->arrUsers as $v){
$this->arrSockets[]=$v['resource'];
}
$this->debug($log);
}
/**
* [debug 输出日志信息]
* @param [string] $str [需要输出的文本信息]
* @return [void]
*/
private function debug($str){
$str=$str."\n";
echo iconv('utf-8','gbk//IGNORE',$str);
}
/**
* [connect 对client的请求进行回应,即握手操作]
* @param [string] $key [clien的socket对应的健,即每个用户有唯一$k并对应socket]
* @param [type] $buffer [接收client请求的所有信息]
* @return [bool]
*/
private function connect($key,$buffer){
//截取Sec-WebSocket-Key的值并加密,其中$key后面的一部分258EAFA5-E914-47DA-95CA-C5AB0DC85B11字符串应该是固定的
$buf = substr($buffer,strpos($buffer,'Sec-WebSocket-Key:')+18);
$key_encrypt = trim(substr($buf,0,strpos($buf,"\r\n")));
$new_key = base64_encode(sha1($key_encrypt."258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true));
//按照协议组合信息进行返回
$new_message = "HTTP/1.1 101 Switching Protocols\r\n";
$new_message .= "Upgrade: websocket\r\n";
$new_message .= "Sec-WebSocket-Version: 13\r\n";
$new_message .= "Connection: Upgrade\r\n";
$new_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n";
socket_write($this->arrUsers[$key]['resource'],$new_message,strlen($new_message));
//对已经握手的client做标志
$this->arrUsers[$key]['handshake']=true;
return true;
}
/**
* [parse 解析数据]
* @param [type] $buffer [接收client请求的所有信息]
* @return [array] [处理好的信息]
*/
private function parse($buffer) {
$decoded = '';
$len = ord($buffer[1]) & 127;
if ($len === 126) {
$masks = substr($buffer, 4, 4);
$data = substr($buffer, 8);
} else if ($len === 127) {
$masks = substr($buffer, 10, 4);
$data = substr($buffer, 14);
} else {
$masks = substr($buffer, 2, 4);
$data = substr($buffer, 6);
}
for ($index = 0; $index < strlen($data); $index++) {
$decoded .= $data[$index] ^ $masks[$index % 4];
}
return json_decode($decoded, true);
}
/**
* [build 将普通信息组装成websocket数据帧]
* @param [type] $msg [对编码后的json]
* @return [bool|string] [description]
*/
private function build($arrmsg) {
$frame = [];
$frame[0] = '81';
$len = strlen($arrmsg);
if ($len < 126) {
$frame[1] = $len < 16 ? '0' . dechex($len) : dechex($len);
} else if ($len < 65025) {
$s = dechex($len);
$frame[1] = '7e' . str_repeat('0', 4 - strlen($s)) . $s;
} else {
$s = dechex($len);
$frame[1] = '7f' . str_repeat('0', 16 - strlen($s)) . $s;
}
$data = '';
$l = strlen($arrmsg);
for ($i = 0; $i < $l; $i++) {
$data .= dechex(ord($arrmsg{$i}));
}
$frame[2] = $data;
$data = implode('', $frame);
return pack("H*", $data);
}
/**
* [broadcast 发送消息]
* @param [array] $data [build处理好的数据]
* @return [type] [description]
*/
private function broadcast($msg_content,$uid='all',$mykey) {
if(empty($msg_content['content'])&&$msg_content['content']!=0){
$this->debug('info : '.date('Y-m-d H:i:s').' | function:broadcast'.' | content is null -> err');
}
if(empty($msg_content['type'])){
$this->debug('info : '.date('Y-m-d H:i:s').' | function:broadcast'.' | type is null -> err');
}
if(empty($msg_content['from'])){
$this->debug('info : '.date('Y-m-d H:i:s').' | function:broadcast'.' | from is null -> err');
}
if($mykey){
$this->debug('info : '.date('Y-m-d H:i:s').' | function:broadcast'.' | mykey is null -> err');
}
$data=$this->build(json_encode($msg_content));
if($uid=='all'){
foreach ($this->arrSockets as $Socket) {
if ($Socket == $this->objMaster) {
continue;
}
socket_write($Socket, $data, strlen($data));
}
}else{
$key=$this->search_uid($uid);
socket_write($this->arrUsers[$key]['resource'], $data, strlen($data));
socket_write($this->arrUsers[$mykey]['resource'], $data, strlen($data));
}
}
/**
* [response_login 登录信息]
* @param [array] $arrmsg [信息数组]
* @param [string] $key [description]
* @return [void]
*/
private function response_login($arrmsg,$key) {
$this->arrUsers[$key]['name']=$arrmsg['name'];
$this->arrUsers[$key]['uid']=$arrmsg['uid'];
$response['type'] = 'system';
$response['from'] = 'login';
$response['name'] = $arrmsg['name'];
$response['content'] = 'ok';
$response['user_list_count'] = count($this->arrUsers)-1;
$response['user_list'] = $this->get_userlist();
$data=$this->build(json_encode($response));
socket_write($this->arrUsers[$key]['resource'], $data, strlen($data));
$this->update_list($arrmsg['name'],$key);
}
private function update_list($name,$key) {
$response['name'] = $name;
$response['type'] = 'system';
$response['from'] = 'list';
$response['content'] = 'ok';
$response['user_list_count'] = count($this->arrUsers)-1;
$response['user_list'] = $this->get_userlist();
$data=$this->build(json_encode($response));
// socket_write($this->arrUsers[$key]['resource'], $data, strlen($data));
foreach ($this->arrSockets as $Socket) {
if ($Socket == $this->objMaster) {
continue;
}
socket_write($Socket, $data, strlen($data));
}
}
private function get_userlist(){
$arrUserlist=array();
foreach ($this->arrUsers as $k => $v) {
if($k != 'server'){
$arrUserlist[]=array('uid'=>$v['uid'],'name'=>$v['name']);
}
}
return $arrUserlist;
}
/**
* [search_uid 根据UID查找KEY]
* @param [type] $uid [客户端UID]
* @return [string] [对应的KEY]
*/
private function search_uid($uid){
if(!empty($uid)){
foreach ($this->arrUsers as $k => $v){
if($k != 'server'){
if($v['uid']==$uid){
return $k;
}
}
}
}
}
}
?>
html部分
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<style>
p {
text-align: left;
padding-left: 20px;
}
a:link { text-decoration: none;color: black}
a:active { text-decoration:blink}
a:hover { text-decoration:underline;color: red}
a:visited { text-decoration: none;color: green}
</style>
</head>
<body>
<div style="width: 800px;height: 600px;margin: 30px auto;text-align: center">
<div style="width: 800px;border: 1px solid gray;height: 100%;">
<div style="width: 130px;height: 300px;float: left;text-align: left;">
<div id="user_list" style="overflow: auto;">
</div>
<p><span>当前在线:</span><span id="user_num">0</span></p>
</div>
<div id="msg_list" style="width: 83.5%;border: 1px solid gray; height: 99.9%;;overflow: scroll;float: left;">
</div>
<br>
<textarea id="msg_box" rows="6" cols="50" onkeydown="confirm(event)" style="width: 800px; height: 50px"></textarea><br>
<input type="file" id="img_upload" style="display:none;" value="图片" />
<input type="button" id="img_button" value="图片" onclick="img_upload.click()" style="width: 200px; height: 50px;float: left;">
<input type="button" id='send_button' value="发送" onclick="send()" style="width: 600px; height: 50px">
</div>
</body>
</html>
<script type="text/javascript">
// 存储用户名到全局变量,握手成功后发送给服务器
var img=Array();
var img_upload=document.getElementById("img_upload");
img_upload.addEventListener('change',readFile,false);
var send_button=document.getElementById("send_button");
var user_id='all';
var u_name = '';
var uname = prompt('请输入用户名',);
var uid = '';
var ws = new WebSocket("ws://192.168.1.85:8080");
ws.onopen = function () {
var user_info = {'type': 'login', 'name': uname,'uid':uid};
sendMsg(user_info);
};
/**
* 分析服务器返回信息
*
* msg.type : user 普通信息;system 系统信息;handshake 握手信息;login 登陆信息; logout 退出信息;
* msg.from : 消息来源
* msg.content: 消息内容
*/
ws.onmessage = function (e) {
var bool =false;
var msg = JSON.parse(e.data);
var sender, user_name, user_list_count, change_type;
console.log(msg);/////////////////////////////
switch (msg.type) {
case 'system':
switch(msg.from){
case 'system':
sender = '系统消息 : ';
bool=true;
break;
case 'login':
sender = '系统消息 -> 登录状态 -> ';
user_name = msg.name;
change_type = msg.from;
uid = msg.uid;
bool=true;
break;
case 'list':
user_name = msg.name;
user_list_count = msg.user_list_count;
user_list = msg.user_list;
change_type = msg.from;
dealUser(user_name, change_type, user_list_count,user_list);
bool=false;
break;
}
break;
case 'user_msg':
switch(msg.msg_type){
case 'img':
switch(msg.img_state){
case 'end':
img[msg.from]+=msg.content;
sender = msg.from + ':';
msg.content='<img src="'+img[msg.from]+'" alt="" style="width: 100%;height: 100%" />';
bool=true;
break;
case 'start':
img[msg.from]='';
img[msg.from]+=msg.content;
break;
default:
img[msg.from]+=msg.content;
break;
}
break;
case 'txt':
if(msg.uid=='all'){
sender = msg.from + ': ';
}else{
if(msg.uid==uid){
sender = msg.from + ' 对你说: ';
}else{
sender = '你对'+u_name+ '说: ';
}
}
msg.content=msg.content.replace(/</g, "<").replace(/>/g, ">");
bool=true;
break;
}
break;
}
if(bool){
var data = sender + msg.content;
listMsg(data);
}
};
ws.onerror = function () {
var data = "系统消息 : 连接退出.";
listMsg(data);
};
ws.onclose=function(){
var data = "系统消息 : 服务端关闭.";
listMsg(data);
}
/**
* 在输入框内按下回车键时发送消息
*
* @param event
*
* @returns {boolean}
*/
function confirm(event) {
var key_num = event.keyCode;
if (13 == key_num) {
send();
} else {
return false;
}
}
/**
* 发送并清空消息输入框内的消息
*/
function send() {
var msg_box = document.getElementById("msg_box");
var content = msg_box.value;
var reg = new RegExp("\r\n", "g");
content = content.replace(reg, "");
var msg = {'content': content.trim(), 'type': 'user_msg','msg_type': 'txt','uid':user_id};
if(user_id==uid){
alert('不能与自己对话!');
}else{
sendMsg(msg);
}
msg_box.value = '';
// todo 清除换行符
}
/**
* 将消息内容添加到输出框中,并将滚动条滚动到最下方
*/
function listMsg(data) {
var msg_list = document.getElementById("msg_list");
var msg = document.createElement("p");
msg.innerHTML = data;
msg_list.appendChild(msg);
msg_list.scrollTop = msg_list.scrollHeight;
}
/**
* 处理用户登陆消息
*
* @param user_name 用户名
* @param type login/logout
* @param name_list 用户列表
*/
function dealUser(user_name, type, name_list_count,user_list) {
var user_list_dom = document.getElementById("user_list");
var user_num = document.getElementById("user_num");
user_list_dom.innerHTML='';
var lis = document.createElement("p");
lis.innerHTML = "<a id='a_all' href=\"javascript:void(0);\" onclick=\"checkedid('all','所有人')\">所有人</a>";
user_list_dom.appendChild(lis);
for (var i = 0; i < user_list.length; i++) {
lis = document.createElement("p");
lis.innerHTML = "<a id='a_"+user_list[i].uid+"' href=\"javascript:void(0);\" onclick=\"checkedid('"+user_list[i].uid+"','"+user_list[i].name+"')\">"+user_list[i].name+"</a>";
user_list_dom.appendChild(lis);
}
user_num.innerHTML = name_list_count;
user_list_dom.scrollTop = user_list_dom.scrollHeight;
var change = type == 'list' ? '上线' : '下线';
var data = '系统消息: ' + user_name + ' 已' + change;
listMsg(data);
}
/**
* 将数据转为json并发送
* @param msg
*/
function sendMsg(msg) {
var data = JSON.stringify(msg);
// console.log(data);
ws.send(data);
}
function readFile(){
var file=this.files[0];
if(!/image\/\w+/.test(file.type)){
alert("请确保文件为图像类型");
return false;
}
var reader=new FileReader();
reader.readAsDataURL(file);
reader.onload=function(){
if(this.result.length>1399895){
alert('图片不能大于1MB否则不保证质量');
return;
}
var while_i=0;
var len=1024;
var img_i=0;
var img=Array();
while(true){
content=this.result.substr(while_i,len);
if(this.result.length<=while_i){
break;
}
var leni=while_i;
while_i+=len;
if(while_i>=this.result.length){
len=this.result.length;
}
img[img_i]=content;
img_i++;
}
var time=50;
var senlen=0;
var reslen=this.result.length;
for(var i=0;i<img.length;i++){
(function(i){
setTimeout(function(){
senlen+=img[i].length;
img_button.value='发送中:'+senlen+'/'+reslen;
if(i==0){
msg = {'img_state': 'start', 'type': 'user_msg','msg_type': 'img','content': img[i],'uid':user_id};
sendMsg(msg);
}else if((i+1)==img.length){
msg = {'img_state': 'end', 'type': 'user_msg','msg_type': 'img','content': img[i],'uid':user_id};
sendMsg(msg);
img_button.value='图片';
}else{
msg = {'img_state': 'body','content': img[i], 'type': 'user_msg','msg_type': 'img','uid':user_id};
sendMsg(msg);
}
}, time);
})(i)
time+=10;
}
}
}
function checkedid(id,name){
console.log(user_id+' - >user_id');
console.log(uid+' - >uid');
user_id=id;
u_name=name;
}
</script>
c#部分
使用了CsharpJson
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using CsharpJson;
using System.Threading;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
bool b = false;
IPAddress ip = IPAddress.Parse("192.168.1.85");
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}
private void Form1_Load(object sender, EventArgs e)
{
try
{
clientSocket.Connect(new IPEndPoint(ip, 8080)); //配置服务器IP与端口
txt_msg.AppendText("连接服务器成功\n");
Thread thread = new Thread(start);
thread.Start();
JsonObject obj = new JsonObject();
obj.Add("type", "login");
obj.Add("name", "c#");
obj.Add("uid", 123);
JsonDocument doc1 = new JsonDocument();
doc1.Object = obj;
string val = doc1.ToJson();
clientSocket.Send(Encoding.Default.GetBytes(val));
clientSocket.Send(Encoding.Default.GetBytes(val));
}
catch
{
txt_msg.AppendText("连接服务器失败\n");
return;
}
}
private void start()
{
int receiveLength = 0;
while (true)
{
try
{
byte[] result = new byte[1024];
receiveLength = clientSocket.Receive(result);
if (receiveLength == 0)
{
continue;
}
JsonDocument doc = JsonDocument.FromString(Encoding.Default.GetString(result, 2, receiveLength));
if (doc.IsObject())
{
JsonObject jsobj = doc.Object;
if (jsobj["type"].ToString()== "system")
{
string msg = "系统消息:";
if (jsobj["from"].ToString()== "login")
{
if (jsobj["content"].ToString() != "ok")
{
txt_msg.AppendText(msg+"登录失败,可能由用户名或ID不可用" +"\n");
}
else
{
this.txt_msg.Invoke(new Action(() =>
{
txt_msg.AppendText(msg + "登录成功" + "\n");
txt_msg.AppendText(msg + "当前在线人数 " + jsobj["user_list_count"].ToInt() + "人\n");
txt_msg.AppendText(msg + jsobj["user_list"].ToArray() + "人\n");
var a = jsobj["user_list"].ToArray();
for(int i = 0; i< a.Count;i++)
{
var b = a[i].ToObject();
switch (b["uid"].Valuetype)
{
case JsonType.STRING:
txt_msg.AppendText(b["uid"].ToString() + "" + "\n");
break;
case JsonType.NUMBER:
txt_msg.AppendText(b["uid"].ToInt() + "" + "\n");
break;
}
}
//jsobj["user_list"].ToArray();
}));
}
}
}
else
{
string msg = "";
if (jsobj["type"].ToString() == "user_msg")
{
if (jsobj["msg_type"].Valuetype == JsonType.STRING)
{
msg = unicode(jsobj["from"].ToString()) + " : ";
}
else
{
msg = jsobj["from"].ToInt() + " : ";
}
if (jsobj["msg_type"].ToString()=="txt")
{
if (jsobj["msg_type"].Valuetype == JsonType.STRING)
{
msg += unicode(jsobj["content"].ToString());
}else if (jsobj["msg_type"].Valuetype == JsonType.NUMBER)
{
msg += jsobj["content"].ToString();
}
}
}
txt_msg.AppendText(msg + "\r\n");
}
}
else
{
Console.WriteLine(Encoding.Default.GetString(result, 2, receiveLength-2) + "\n");
//clientSocket.Send(buffer);
}
}
catch (Exception e)
{
txt_msg.AppendText("与服务端断开连接\n");
break;
}
//txt_msg.AppendText("接收服务器消息:{0}", Encoding.ASCII.GetString(result, 0, receiveLength));
}
}
private void upui()
{
txt_msg.Text = DateTime.Now.ToLongTimeString(); //为同一线程则直接刷新label1
}
private string unicode (string str)
{
//UNICODE字符转为中文
//str = "//u4e2d//u6587";
string outStr = "";
if (!string.IsNullOrEmpty(str))
{
string[] strlist = str.Replace("\\", "").Split('u');
try
{
for (int i = 1; i < strlist.Length; i++)
{
//将unicode字符转为10进制整数,然后转为char中文字符
outStr += (char)int.Parse(strlist[i], System.Globalization.NumberStyles.HexNumber);
}
}
catch (FormatException ex)
{
outStr = ex.Message;
}
}
return outStr;
}
private void btn_sen_Click(object sender, EventArgs e)
{
//JsonObject obj = new JsonObject();
//obj.Add("type", "login");
//obj.Add("name", "c#");
//obj.Add("uid", 121235673);
//JsonDocument doc1 = new JsonDocument();
//doc1.Object = obj;
//string val = doc1.ToJson();
//clientSocket.Send(Encoding.Default.GetBytes(val));
}
}
}
声明:
本文采用
BY-NC-SA
协议进行授权,如无注明均为原创,转载请注明转自
一颗大萝北
本文地址: [即时通讯]使用php写服务端,html和c#winfrom写客户端[弃坑中]
本文地址: [即时通讯]使用php写服务端,html和c#winfrom写客户端[弃坑中]