以下示例程序實現簡單的socket通信,可以開多個客戶端。本機測試通過,未做聯機測試。
server:
using system.net;
using system.net.sockets;
using system.threading;
using system.collections;
namespace mysocketserver1
{
public partial class form1 : form
{
private ipaddress serverip = ipaddress.parse("127.0.0.1");//以本機作測試
private ipendpoint serverfulladdr;//完整終端地址
private socket sock;
private system.timers.timer mytimer;
private arraylist alsock;//當建立了多個連接時用于保存連接
public form1()
{
initializecomponent();
}
private void btstart_click(object sender, eventargs e)
{
serverfulladdr = new ipendpoint(serverip, 1000);//取端口號1000
//構造socket對象,套接字類型為“流套接字”,指定五元組中的協議元
sock = new socket(addressfamily.internetwork, sockettype.stream,
protocoltype.tcp);
//指定五元組中的本地二元,即本地主機地址和端口號
sock.bind(serverfulladdr);
//監聽是否有連接傳入,指定掛起的連接隊列的最大值為20
sock.listen(20);
alsock = new arraylist();
//構造定時器,時間間隙為1秒,即每隔一秒執行一次accept()方法,以獲取連接請求隊列中//第一個掛起的連接請求
mytimer =new system.timers.timer(1000);
mytimer.elapsed +=new system.timers.elapsedeventhandler(mytimer_elapsed);
mytimer.enabled = true;
}
private void mytimer_elapsed(object sender, system.timers.elapsedeventargs e)
{
mytimer.enabled = false;
//執行accept(),當掛起隊列為空時將阻塞本線程,同時由于上一語句,定時器將停止,直//至有連接傳入
socket acceptsock = sock.accept();
//將accept()產生的socket對象存入arraylist
alsock.add(acceptsock);
// 構造threading.timer對象,這將導致程序另啟線程。線程將執行回調函數,該委托限制//函數參數須為object型。threading.timer構造器的第二個參數即傳入回調函數的參數;第//三個參數指定調用回調函數之前的延時,取0則立即啟動;最后一個參數指定調用回調函數//的時間間隔,取0則只執行一次。
system.threading.timer ti = new system.threading.timer(new
timercallback(receivemsg), acceptsock, 0, 0);
mytimer.enabled = true;
}
private void receivemsg(object obj)
{
socket acceptsock = (socket)obj;
try
{
while (true)
{
byte[] bytearray = new byte[100];
acceptsock.receive(bytearray);//接收數據
//將字節數組轉成字符串
string strrec = system.text.encoding.utf8.getstring(bytearray);
if (this.rtbreceive.invokerequired)
{
this.rtbreceive.invoke(new eventhandler(this.changericktextbox), new
object[] { strrec, eventargs.empty });
}
}
}
catch(exception ex)
{
acceptsock.close();
messagebox.show("s:receive message error"+ex.message);
}
}
private void changericktextbox(object obj,eventargs e)
{
string s = system.convert.tostring(obj);
this.rtbreceive.appendtext(s + environment.newline);
}
private void btsend_click(object sender, eventargs e)
{
socket sc=null;
byte[] bytesend =
system.text.encoding.utf8.getbytes(this.tbsend.text.tochararray());
try
{
//同時存在若干個客戶端連接時,在textbox1中輸入要發送的是哪個連接
int index = int.parse(this.textbox1.text.trim());
sc = (socket)alsock[index - 1];
//發送數據
sc.send(bytesend);
}
catch(exception ex)
{
if(sc != null)
{
sc.close();
}
messagebox.show("s:send message error"+ex.message);
}
}
private void btclose_click(object sender, eventargs e)
{
try
{
application.exit();
}
catch (exception ex)
{
messagebox.show("s:close socket error" + ex.message);
}
}
}
}
== == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
client:
using system.net;
using system.net.sockets;
using system.threading;
namespace mysocketclient1
{
public partial class form1 : form
{
private ipaddress serverip = ipaddress.parse("127.0.0.1");
private ipendpoint serverfulladdr;
private socket sock;
public form1()
{
initializecomponent();
}
private void btconnect_click(object sender, eventargs e)
{
try
{
serverfulladdr = new ipendpoint(serverip, 1000);
sock = new socket(addressfamily.internetwork, sockettype.stream,
protocoltype.tcp);
sock.connect(serverfulladdr);//建立與遠程主機的連接
//啟動新線程用于接收數據
thread t = new thread(new threadstart(receivemsg));
t.name = "receive message";
//一個線程或者是后臺線程或者是前臺線程。后臺線程與前臺線程類似,區別是后臺線//程不會防止進程終止。一旦屬于某一進程的所有前臺線程都終止,公共語言運行庫就//會通過對任何仍然處于活動狀態的后臺線程調用 abort 來結束該進程。
t.isbackground = true;
t.start();
}
catch(exception ex)
{
messagebox.show(ex.message);
}
}
private void receivemsg()
{
try
{
while (true)
{
byte[] byterec = new byte[100];
this.sock.receive(byterec);
string strrec = system.text.encoding.utf8.getstring(byterec);
if (this.rtbreceive.invokerequired)
{
this.rtbreceive.invoke(new eventhandler(changertb), new object[]
{ strrec, eventargs.empty });
}
}
}
catch(exception ex)
{
messagebox.show("receive message error"+ex.message);
}
}
private void changertb(object obj, eventargs e)
{
string s = system.convert.tostring(obj);
this.rtbreceive.appendtext(s + environment.newline);
}
private void btsend_click(object sender, eventargs e)
{
byte[] bytesend =
system.text.encoding.utf8.getbytes(this.tbsend.text.tochararray());
try
{
this.sock.send(bytesend);
}
catch
{
messagebox.show("send message error");
}
}
private void btclose_click(object sender, eventargs e)
{
try
{
this.sock.shutdown(socketshutdown.receive);
this.sock.close();
application.exit();
}
catch
{
messagebox.show("exit error");
}
}
}
}
不解之處:
client端紅色標注語句:this.sock.shutdown(socketshutdown.receive),如改成
this.sock.shutdown(socketshutdown.both);或this.sock.shutdown(socketshutdown.send);
則當點擊cloce按鈕時,cpu使用率瘋漲到100%,而使用this.sock.shutdown(socketshutdown.receive);
或不調用shutdown()方法則沒有這個問題。難道客戶端不應該用shutdown()?
新聞熱點
疑難解答
圖片精選