我编写了一个客户端和服务器应用程序,我需要用它来连接我在C#中制作的跳棋游戏。我已经连接了客户端和服务器,服务器可以重复发送客户端消息来更新标签但是当客户端尝试发送消息时会抛出错误
“由于没有连接套接字而且(当使用sendto调用在数据报套接字上发送时)没有提供地址,因此不允许发送或接收数据的请求。”
到目前为止,这是我的客户端和服务器。
客户 -
public partial class Form1 : Form //main form that establishes connection
{
Form2 form2 = new Form2();
Socket sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Socket acc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint endPoint;
static byte[] Buffer { get; set; }
string text;
public Form1()
{
InitializeComponent();
}
private void button1_Click_1(object sender, EventArgs e)
{
Thread rec = new Thread(recMsg);
Thread t = new Thread(ThreadProc);
t.Start(); //starts a form that will call the sendMsg on a button click
endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8887);
try
{
sck.Connect(endPoint);
}
catch
{
Console.WriteLine("unable to connect");
}
rec.Start();
text = textBox1.Text;
sendMsg(text);
}
public void sendMsg(string s)
{
//bool x = true;
//while (true)
//{
//Thread.Sleep(500);
//if (x == true)
//{
byte[] msgBuffer = Encoding.ASCII.GetBytes(s);
sck.Send(msgBuffer); //error comes here when i try to send a message from form2 says it isn't connected and has no address
// x = false;
//}
//} the commented out part doesn't effect how the send works it sends once and can't again, I think the problem is that the thread which establishes the connection dies but don't know how to solve.
}
public void recMsg()
{
while (true)
{
Thread.Sleep(500);
byte[] Buffer = new byte[255];
int rec = sck.Receive(Buffer, 0, Buffer.Length, 0);
Array.Resize(ref Buffer, rec);
form2.SetText(Encoding.Default.GetString(Buffer));
}
}
private void button2_Click(object sender, EventArgs e)
{
sck.Close();
}
public void ThreadProc()
{
form2.ShowDialog();
}
}
表单2有一个label1,textbox1和button1,主要操作表单将接受输入并调用Form1 sendMsg()
public partial class Form2 : Form
{
delegate void SetTextCallback(string text);
Form1 form1;
public Form2()
{
InitializeComponent();
}
public void SetText(string text)
{
if (InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
Invoke(d, new object[] { text });
}
else
{
label1.Text = text;
}
}
private void button1_Click(object sender, EventArgs e)
{
form1 = new Form1();
form1.sendMsg(textBox1.Text);
}
}
SERVER -
class Program
{
static Form1 form1 = new Form1();
static Form2 form2 = new Form2();
static byte[] buffer { get; set; }
static Socket sck, acc;
static string name;
static void Main(string[] args)
{
if (name == null)
{
Thread t = new Thread(ThreadProc);
t.Start();
}
Thread rec = new Thread(recMsg);
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sck.Bind(new IPEndPoint(0, 8887));
Console.WriteLine("Your local IP address is: " + getIP());
Console.WriteLine("Awaiting Connection");
sck.Listen(0);
acc = sck.Accept();
Console.WriteLine(" >> Accept connection from client");
rec.Start();
sendMsg();
}
static string getIP()
{
string hostName = System.Net.Dns.GetHostName();
IPHostEntry ipEntry = System.Net.Dns.GetHostEntry(hostName);
IPAddress[] addr = ipEntry.AddressList;
return addr[addr.Length - 1].ToString();
}
static void recMsg()
{
while (acc.Connected)
{
Thread.Sleep(500);
byte[] Buffer = new byte[255];
int rec = acc.Receive(Buffer, 0, Buffer.Length, 0);
Array.Resize(ref Buffer, rec);
form2.SetText(Encoding.Default.GetString(Buffer));
}
}
public void btnClick(string s)
{
name = s;
Console.WriteLine("Name: " + name);
System.Threading.Thread r = new System.Threading.Thread(new System.Threading.ThreadStart(ThreadProc2));
r.Start();
}
public void sendMSG(string s)
{
try
{
buffer = Encoding.Default.GetBytes(s);
acc.Send(buffer);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
static void sendMsg()
{
try
{
buffer = Encoding.Default.GetBytes(name);
acc.Send(buffer);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
public static void ThreadProc()
{
form1.ShowDialog();
}
public static void ThreadProc2()
{
form2.ShowDialog();
}
}
Form1 - 要求输入名称的初学者表单,这个表单可能只是用来构建我的基本服务器,最终将需要用于跳棋游戏。
public partial class Form1 : Form
{
Program program;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
this.Hide();
program = new Program();
program.btnClick(textBox1.Text);
}
}
Form2用作我客户端Form2的接口,基本上有一个标签,文本框和调用sendMsg()的按钮
public partial class Form2 : Form
{
delegate void SetTextCallback(string text);
Program program = new Program();
public Form2()
{
InitializeComponent();
}
public void SetText(string text)
{
if (InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.label2.Text = text;
}
}
private void button1_Click(object sender, EventArgs e)
{
program.sendMSG(textBox1.Text);
}
}
总结一下,这个程序将连接,服务器可以多次向客户端发送数据并更新标签。客户端将在第一时间向服务器发送数据,然后抛出错误。
答案 0 :(得分:3)
为什么不使用异步套接字?这是一些代码:
// Server socket
class ControllerSocket : Socket, IDisposable
{
// MessageQueue queues messages to be processed by the controller
public Queue<MessageBase> messageQueue = null;
// This is a list of all attached clients
public List<Socket> clients = new List<Socket>();
#region Events
// Event definitions handled in the controller
public delegate void SocketConnectedHandler(Socket socket);
public event SocketConnectedHandler SocketConnected;
public delegate void DataRecievedHandler(Socket socket, int bytesRead);
public event DataRecievedHandler DataRecieved;
public delegate void DataSentHandler(Socket socket, int length);
public event DataSentHandler DataSent;
public delegate void SocketDisconnectedHandler();
public event SocketDisconnectedHandler SocketDisconnected;
#endregion
#region Constructor
public ControllerSocket(int port)
: base(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
{
// Create the message queue
this.messageQueue = new Queue<MessageBase>();
// Acquire the host address and port, then bind the server socket
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port);
this.Bind(localEndPoint);
}
#endregion
// Starts accepting client connections
public void StartListening()
{
this.Listen(100);
this.BeginAccept(AcceptCallback, this);
}
// Connects to a client
private void AcceptCallback(IAsyncResult ar)
{
Socket listener = (Socket)ar.AsyncState;
Socket socket = listener.EndAccept(ar);
try
{
// Add the connected client to the list
clients.Add(socket);
// Notify any event handlers
if (SocketConnected != null)
SocketConnected(socket);
// Create an initial state object to hold buffer and socket details
StateObject state = new StateObject();
state.workSocket = socket;
state.BufferSize = 8192;
// Begin asynchronous read
socket.BeginReceive(state.Buffer, 0, state.BufferSize, 0,
ReadCallback, state);
}
catch (SocketException)
{
HandleClientDisconnect(socket);
}
finally
{
// Listen for more client connections
StartListening();
}
}
// Read data from the client
private void ReadCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
Socket socket = state.workSocket;
try
{
if (socket.Connected)
{
// Read the socket
int bytesRead = socket.EndReceive(ar);
// Deserialize objects
foreach (MessageBase msg in MessageBase.Receive(socket, bytesRead, state))
{
// Add objects to the message queue
lock (this.messageQueue)
messageQueue.Enqueue(msg);
}
// Notify any event handlers
if (DataRecieved != null)
DataRecieved(socket, bytesRead);
// Asynchronously read more client data
socket.BeginReceive(state.Buffer, state.readOffset, state.BufferSize - state.readOffset, 0,
ReadCallback, state);
}
else
{
HandleClientDisconnect(socket);
}
}
catch (SocketException)
{
HandleClientDisconnect(socket);
}
}
// Send data to a specific client
public void Send(Socket socket, MessageBase msg)
{
try
{
// Serialize the message
byte[] bytes = msg.Serialize();
if (socket.Connected)
{
// Send the message
socket.BeginSend(bytes, 0, bytes.Length, 0, SendCallback, socket);
}
else
{
HandleClientDisconnect(socket);
}
}
catch (SocketException)
{
HandleClientDisconnect(socket);
}
}
// Broadcast data to all clients
public void Broadcast(MessageBase msg)
{
try
{
// Serialize the message
byte[] bytes = msg.Serialize();
// Process all clients
foreach (Socket client in clients)
{
try
{
// Send the message
if (client.Connected)
{
client.BeginSend(bytes, 0, bytes.Length, 0, SendCallback, client);
}
else
{
HandleClientDisconnect(client);
}
}
catch (SocketException)
{
HandleClientDisconnect(client);
}
}
}
catch (Exception e)
{
// Serialization error
Console.WriteLine(e.ToString());
}
}
// Data sent to a client socket
private void SendCallback(IAsyncResult ar)
{
try
{
Socket socket = (Socket)ar.AsyncState;
if (socket.Connected)
{
// Complete sending the data
int bytesSent = socket.EndSend(ar);
// Notify any attached handlers
if (DataSent != null)
DataSent(socket, bytesSent);
}
else
{
HandleClientDisconnect(socket);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void HandleClientDisconnect(Socket client)
{
// Client socket may have shutdown unexpectedly
if (client.Connected)
client.Shutdown(SocketShutdown.Both);
// Close the socket and remove it from the list
client.Close();
clients.Remove(client);
// Notify any event handlers
if (SocketDisconnected != null)
SocketDisconnected();
}
// Close all client connections
public void Dispose()
{
foreach (Socket client in clients)
{
if (client.Connected)
client.Shutdown(SocketShutdown.Receive);
client.Close();
}
}
}
// Client socket
class ReceiverSocket : Socket
{
// MessageQueue queues messages to be processed by the controller
public Queue<MessageBase> messageQueue = null;
#region Events
// Event definitions handled in the controller
public delegate void SocketConnectedHandler(Socket socket);
public event SocketConnectedHandler SocketConnected;
public delegate void DataRecievedHandler(Socket socket, MessageBase msg);
public event DataRecievedHandler DataRecieved;
public delegate void DataSentHandler(Socket socket, int length);
public event DataSentHandler DataSent;
public delegate void SocketDisconnectedHandler();
public event SocketDisconnectedHandler SocketDisconnected;
private IPEndPoint remoteEP = null;
#endregion
#region Constructor
public ReceiverSocket(int port)
: base(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
{
// Create the message queue
messageQueue = new Queue<MessageBase>();
// Acquire the host address and port
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
remoteEP = new IPEndPoint(ipAddress, port);
}
#endregion
// Connect to the server
public void Connect()
{
this.BeginConnect(remoteEP, ConnectCallback, this);
}
// Server connected
private void ConnectCallback(IAsyncResult ar)
{
// Console.WriteLine("Connect Callback");
try
{
Socket client = (Socket)ar.AsyncState;
if (client.Connected)
{
client.EndConnect(ar);
// Console.WriteLine("Connect Callback - Connected");
// Create an initial state object to hold buffer and socket details
StateObject state = new StateObject();
state.workSocket = client;
state.BufferSize = 8192;
// Notify any event handlers
if (SocketConnected != null)
SocketConnected(client);
// Begin asynchronous read
client.BeginReceive(state.Buffer, state.readOffset, state.BufferSize - state.readOffset, 0,
ReceiveCallback, state);
}
else
{
// Console.WriteLine("Connect Callback - Reconnect");
Thread.Sleep(5000);
Connect();
}
}
catch (Exception ex)
{
// Attempt server reconnect
Reconnect();
}
}
// Read data from the server
private void ReceiveCallback(IAsyncResult ar)
{
try
{
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read the socket
if (client.Connected)
{
int bytesRead = client.EndReceive(ar);
// Deserialize objects
foreach (MessageBase msg in MessageBase.Receive(client, bytesRead, state))
{
// Add objects to the message queue
lock (this.messageQueue)
this.messageQueue.Enqueue(msg);
}
// Notify any event handlers
if (DataRecieved != null)
DataRecieved(client, null);
// Asynchronously read more server data
client.BeginReceive(state.Buffer, state.readOffset, state.BufferSize - state.readOffset, 0,
ReceiveCallback, state);
}
else
{
Reconnect();
}
}
catch (SocketException)
{
// Attempt server reconnect
Reconnect();
}
}
public void Send(MessageBase msg)
{
try
{
// Serialize the message
byte[] bytes = msg.Serialize();
if (this.Connected)
{
// Send the message
this.BeginSend(bytes, 0, bytes.Length, 0, SendCallback, this);
}
else
{
Reconnect();
}
}
catch (SocketException sox)
{
// Attempt server reconnect
Reconnect();
}
catch (Exception ex)
{
int i = 0;
}
}
private void SendCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket)ar.AsyncState;
if (client.Connected)
{
// Complete sending the data
int bytesSent = client.EndSend(ar);
// Notify any event handlers
if (DataSent != null)
DataSent(client, bytesSent);
}
else
{
Reconnect();
}
}
catch (SocketException)
{
Reconnect();
}
}
// Attempt to reconnect to the server
private void Reconnect()
{
try
{
// Disconnect the original socket
if (this.Connected)
this.Disconnect(true);
this.Close();
// Notify any event handlers
if (SocketDisconnected != null)
SocketDisconnected();
}
catch (Exception e)
{
// Console.WriteLine(e.ToString());
}
}
}
// Encapsulates information about the socket and data buffer
public class StateObject
{
public Socket workSocket = null;
public int readOffset = 0;
public StringBuilder sb = new StringBuilder();
private int bufferSize = 0;
public int BufferSize
{
set
{
this.bufferSize = value;
buffer = new byte[this.bufferSize];
}
get { return this.bufferSize; }
}
private byte[] buffer = null;
public byte[] Buffer
{
get { return this.buffer; }
}
}
您需要做的就是插入自己的消息。
请记住,套接字流可能(并且大部分时间都是)包含部分消息。因此,最好将消息的长度作为消息的第一个字节发送。您还必须通过在读取之间组合部分消息来相应地管理读取缓冲区。查看以下消息基类。
public partial class MessageBase
{
// Virtual Execute method following the Command pattern
public virtual string Execute(Socket socket) { return string.Empty; }
protected virtual bool MustEncrypt
{
get { return false; }
}
// Binary serialization
public byte[] Serialize()
{
using (MemoryStream stream = new MemoryStream())
{
using (DeflateStream ds = new DeflateStream(stream, CompressionMode.Compress, true))
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(ds, this);
ds.Flush();
}
byte[] bytes = stream.GetBuffer();
byte[] bytes2 = new byte[stream.Length];
Buffer.BlockCopy(bytes, 0, bytes2, 0, (int)stream.Length);
// Array.Copy(bytes, bytes2, stream.Length);
if (this.MustEncrypt)
bytes2 = RijndaelEncrptor.Instance.Encrypt(bytes2);
// Create a buffer large enough to hold the encrypted message and size bytes
byte[] data = new byte[8 + bytes2.Length];
// Add the message size
BitConverter.GetBytes(bytes2.Length).CopyTo(data, 0);
BitConverter.GetBytes(this.MustEncrypt).CopyTo(data, 4);
// Add the message data
bytes2.CopyTo(data, 8);
return data;
}
}
static public MessageBase Deserialize(byte[] buffer)
{
int length = BitConverter.ToInt32(buffer, 0);
bool mustDecrypt = BitConverter.ToBoolean(buffer, 4);
MessageBase b = null;
try
{
b = MessageBase.Deserialize(buffer, 8, length, mustDecrypt);
}
catch { }
return b;
}
static public MessageBase Deserialize(byte[] buffer, int offset, int length, bool mustDecrypt)
{
// Create a buffer and initialize it with data from
// the input buffer offset by the specified offset amount
// and length determined by the specified length
byte[] data = new byte[length];
Buffer.BlockCopy(buffer, offset, data, 0, length);
// Array.Copy(buffer, offset, data, 0, length);
// Decrypt message
if (mustDecrypt)
data = RijndaelEncrptor.Instance.Decrypt(data);
// Deserialize the binary data into a new object of type MessageBase
using (MemoryStream stream = new MemoryStream(data))
{
using (DeflateStream ds = new DeflateStream(stream, CompressionMode.Decompress, false))
{
BinaryFormatter formatter = new BinaryFormatter();
try
{
return formatter.Deserialize(ds) as MessageBase;
}
catch
{
return null;
}
}
}
}
static public IEnumerable<MessageBase> Receive(Socket client, int bytesReceived, StateObject state)
{
// Total buffered count is the bytes received this read
// plus any unprocessed bytes from the last receive
int bufferLen = bytesReceived + state.readOffset;
// Reset the next read offset in the case
// this recieve lands on a message boundary
state.readOffset = 0;
// Make sure there are bytes to read
if (bufferLen >= 0)
{
// Initialize the current read position
int readOffset = 0;
// Process the receive buffer
while (readOffset < bufferLen)
{
// Get the message size
int length = BitConverter.ToInt32(state.Buffer, readOffset);
bool mustDecrypt = BitConverter.ToBoolean(state.Buffer, readOffset + 4);
// Increment the current read position by the length header
readOffset += 8;
// Change the buffer size if necessary
if (length + readOffset > state.Buffer.Length)
{
byte[] oldBuffer = new byte[state.BufferSize];
Buffer.BlockCopy(state.Buffer, 0, oldBuffer, 0, state.BufferSize);
// Array.Copy(state.Buffer, oldBuffer, state.BufferSize);
state.BufferSize = length + readOffset;
Buffer.BlockCopy(oldBuffer, 0, state.Buffer, 0, oldBuffer.Length);
// Array.Copy(oldBuffer, state.Buffer, oldBuffer.Length);
}
// Ensure there are enough bytes to process the message
if (readOffset + length <= bufferLen)
yield return MessageBase.Deserialize(state.Buffer, readOffset, length, mustDecrypt);
else
{
// Add back the message length
readOffset -= 8;
// Reorder the receive buffer so unprocessed
// bytes are moved to the start of the array
Buffer.BlockCopy(state.Buffer, 0, state.Buffer, 0, bufferLen - readOffset);
// Array.Copy(state.Buffer, state.Buffer, bufferLen - readOffset);
// Set the receive position to the current read position
// This is the offset where the next socket read will start
state.readOffset = bufferLen - readOffset;
break;
}
// Update the read position by the message length
readOffset += length;
}
}
}
}
上面的代码可以帮到你。
答案 1 :(得分:0)
您确实意识到您的代码永远不会从此处退出:
public void sendMsg(string s)
{
bool x = true;
while (true)
{
Thread.Sleep(500);
if (x == true)
{
byte[] msgBuffer = Encoding.ASCII.GetBytes(s);
sck.Send(msgBuffer);
x = false;
}
}
}
这是一个无限循环,没有中断或返回,也没有办法退出。怎么样:
public void sendMsg(string s)
{
while (true)
{
Thread.Sleep(500);
byte[] msgBuffer = Encoding.ASCII.GetBytes(s);
sck.Send(msgBuffer);
}
}
答案 2 :(得分:0)
找出我的问题的解决方案可能不是标准的方法,但它的工作原理。 这是一个简单的聊天应用程序,可用于连接玩家与玩家游戏在线发送来回移动。
SERVER -
using System;
using System.Net.Sockets;
using System.Text;
using System.Net;
using System.Threading;
using System.Windows.Forms;
namespace testServer
{
class Program
{
static Form1 form1 = new Form1();
static Form2 form2 = new Form2();
static byte[] buffer { get; set; }
static Socket sck, acc;
static string name;
public void setName(string s)
{
name = s;
string[] asdf = new string[2];
}
static string getIP()
{
string hostName = System.Net.Dns.GetHostName();
IPHostEntry ipEntry = System.Net.Dns.GetHostEntry(hostName);
IPAddress[] addr = ipEntry.AddressList;
return addr[addr.Length - 1].ToString();
}
static void Main(string[] args)
{
if (name == null)
{
Thread t = new Thread(ThreadProc);
t.Start();
}
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sck.Bind(new IPEndPoint(0, 8888));
Console.WriteLine("Your local IP address is: " + getIP());
Console.WriteLine("Awaiting Connection");
sck.Listen(100);
acc = sck.Accept();
Console.WriteLine(" >> Accept connection from client");
sendMsg();
while (acc.Connected)
{
Thread.Sleep(500);
byte[] Buffer = new byte[255];
int receive = acc.Receive(Buffer, 0, Buffer.Length, 0);
Array.Resize(ref Buffer, receive);
form2.SetText(Encoding.Default.GetString(Buffer));
}
}
public void btnClick(string s)
{
name = s;
Console.WriteLine("Name: " + name);
System.Threading.Thread r = new System.Threading.Thread(new System.Threading.ThreadStart(ThreadProc2));
r.Start();
}
public void sendMSG(string s)
{
try
{
buffer = Encoding.Default.GetBytes(s);
acc.Send(buffer);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
static void sendMsg()
{
try
{
buffer = Encoding.Default.GetBytes(name);
acc.Send(buffer);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
public static void ThreadProc()
{
form1.ShowDialog();
}
public static void ThreadProc2()
{
form2.ShowDialog();
}
}
}
这是程序类,其他形式与我原来的帖子相同。
客户端 -
using System;
using System.Windows.Forms;
using System.Text;
using System.Net.Sockets;
using System.Threading;
namespace testClient100
{
public partial class Form1 : Form
{
System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient();
NetworkStream serverStream = default(NetworkStream);
string readData = null;
string ipaddress;
public Form1()
{
InitializeComponent();
}
private void getMessage()
{
while (true)
{
serverStream = clientSocket.GetStream();
int buffSize = 0;
byte[] inStream = new byte[10025];
buffSize = clientSocket.ReceiveBufferSize;
serverStream.Read(inStream, 0, buffSize);
string returndata = System.Text.Encoding.ASCII.GetString(inStream);
readData = "" + returndata;
msg();
}
}
private void msg()
{
if (this.InvokeRequired)
this.Invoke(new MethodInvoker(msg));
else
textBox1.Text = textBox1.Text + Environment.NewLine + " >> " + readData;
}
private void button1_Click_1(object sender, EventArgs e)
{
byte[] outStream = System.Text.Encoding.ASCII.GetBytes(textBox2.Text);
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
}
private void button2_Click_1(object sender, EventArgs e)
{
ipaddress = textBox4.Text;
readData = "Conected to Chat Server ...";
msg();
clientSocket.Connect(ipaddress, 8888);
serverStream = clientSocket.GetStream();
byte[] outStream = System.Text.Encoding.ASCII.GetBytes(textBox3.Text);
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
Thread ctThread = new Thread(getMessage);
ctThread.Start();
}
}
}