C++编写的多线程通信程序,代码编译没有错误(vc),可是服务端与客户端就是连接不上,望高手解答
我调试了你的代码,你的代码是没有问题的,虽然不能使用,但是正常的Socket通讯流程是可以进行的。而且我调试的时候服务器和客户端代码都返回通讯成功。accept()返回的socket为124,connect返回0,说明通讯是正常的。你需要从操作系统环境找原因了。
调试截图如下:
服务器端accept返回socket为124
客户端connect返回0
定时器:使用SystemTimersTimer类 SystemTimersTimer t = new SystemTimersTimer(10000);//实例化Timer类,设置间隔时间为10000毫秒; tElapsed += new SystemTimersElapsedEventHandler(theout);//到达时间的时候执行事件; tAutoReset = true;//设置是一直执行(true)还是执行一次(false); tEnabled = true;//是否执行SystemTimersTimerElapsed事件; public void theout(object source, SystemTimersElapsedEventArgs e) { MessageBoxShow("OK!"); } 多线程方面:
我以前写过类似的socket通信,虽然你用的方法和我的不太一样,但我还是感觉有一些问题
接受消息的时候,你用的是while(true)循环,当第一次将消息接受后,缓冲区就为空了,我想你再用循环去接收应该会出问题。
我记得有个poll方法,具体什么用途忘记了(很久没写代码了)你在循环里面加个if (clientsocketPoll(1000, SelectModeSelectRead))判断语句“clientsocket为你需要接收消息的socket”看看能不能解决,或者就用异步也可以,我可以发一下我以前的代码你参考下:
using System;
using SystemCollectionsGeneric;
using SystemComponentModel;
using SystemData;
using SystemDrawing;
using SystemText;
using SystemWindowsForms;
using SystemNet;
using SystemNetSockets;
using SystemThreading;
namespace test4_2
{
public partial class Form1 : Form
{
Socket connectSocket;
//Socket client;
byte[] bytes = new byte[1024];
delegate void listboxDel(string s);
listboxDel listboxdel;
public Form1()
{
InitializeComponent();
textBoxContentFocus();
listboxdel = new listboxDel(listbox);
//为连接指派线程
Thread threadConnect = new Thread(new ThreadStart(Connect));
threadConnectStart();
}
public void listbox(string str)
{
listBox1ItemsAdd(str);
listBox1SelectedIndex = listBox1ItemsCount - 1;
listBox1ClearSelected();
}
//连接方法
public void Connect()
{
try
{
//建立连接socket
connectSocket = new Socket(AddressFamilyInterNetwork,SocketTypeStream,ProtocolTypeTcp);
//开始异步连接
connectSocketBeginConnect(IPAddressParse("1721694152"),
82,
new AsyncCallback(ConnectCallback), //定义回调函数代理
connectSocket); //传递给回调函数的状态
}
catch (Exception e)
{
MessageBoxShow(eMessage);
}
}
//连接方法的回调函数
private void ConnectCallback(IAsyncResult ar)
{
try
{
//从传递的状态中获取套接字,创建一个客户端套接字
Socket client = (Socket)arAsyncState;
//完成挂起的连接操作
clientEndConnect(ar);
listBox1Invoke(listboxdel, "连接服务器成功,可以开始通话!");
clientBeginReceive(bytes, 0, 1000, 0, new AsyncCallback(receivecallback), client);
}
catch (Exception e)
{
ConsoleWriteLine(eToString());
}
}
public void receivecallback(IAsyncResult ar)
{
try
{
Socket client = (Socket)arAsyncState;
int length = clientEndReceive(ar);
listBox1Invoke(listboxdel, EncodingUTF8GetString(bytes, 0, length));
clientBeginReceive(bytes, 0, 1000, 0, new AsyncCallback(receivecallback), client);
}
catch
{
}
}
//发送方法
private void Send(String data)
{
//使用ASCII转换字符串为字节序列
byte[] byteData = EncodingUTF8GetBytes(data); //将字符串转换成字节序列
//开始向远端设备发送数据
connectSocketBeginSend(byteData, 0, byteDataLength, SocketFlagsNone,
new AsyncCallback(SendCallback), connectSocket);
}
//发送方法的回调函数
private void SendCallback(IAsyncResult ar)
{
try
{
//从传递的状态中获取套接字,创建一个客户端套接字
Socket client = (Socket)arAsyncState;
//结束异步数据传输操作,返回传输的字节数
int bytesSent = clientEndSend(ar);
listBox1Invoke(listboxdel, textBoxUserText +":"+ textBoxContentText);
}
catch (Exception e)
{
MessageBoxShow(eToString());
}
}
private void buttonSend_Click(object sender, EventArgs e)
{
Send(textBoxUserText+":"+textBoxContentText);
}
}
}
1、使用socekt通信一般步骤
1)服务器端:socker()建立套接字,绑定(bind)并监听(listen),用accept()等待客户端连接。
2)客户端:socker()建立套接字,连接(connect)服务器,连接上后使用send()和recv(),在套接字上写读数据,直至数据交换完毕,closesocket()关闭套接字。
3)服务器端:accept()发现有客户端连接,建立一个新的套接字,自身重新开始等待连接。该新产生的套接字使用send()和recv()写读数据,直至数据交换完毕,closesocket()关闭套接字。
2、多个客户端同时连接在一个服务器上
这时候服务器端应该使用多线程,每连接上一个客户端就给该客户端开启一个线程。监听端口的时候也要单独开一个线程、不然会阻塞主线程。这样做有一个明显的缺点,就是有N个客户端请求连接时,就会有N个线程,对程序的性能和计算机的性能影响很大,可以使用线程池进行管理。
使用线程池的好处:主要用于减少因频繁创建和销毁线程带来开销,因此那些经常使用且执行时间短的线程需要用线程池来管理。
3、C#版代码如下
服务器端代码:
[html] view plain copy
using System;
using SystemCollectionsGeneric;
using SystemLinq;
using SystemText;
using SystemNet;
using SystemNetSockets;
using SystemThreading;
using SystemIO;
namespace SockServer
{
class Program
{
static void Main(string[] args)
{
try
{
//把ip地址转换为实例
IPAddress ipa = IPAddressParse("127001");
//监听端口8001
TcpListener mylsn = new TcpListener(ipa, 8001);
//开启监听
mylsnStart();
//输出监听成功的信息
ConsoleWriteLine("在8001启动服务,等待连接");
//等待处理接入连接请求
while (true)
{
Socket mysock = mylsnAcceptSocket();
ConsoleWriteLine("有连接,连接来自" + mysockRemoteEndPoint);
work w = new work();
wmysock = mysock;
wmylsn = mylsn;
Thread t = new Thread(new ThreadStart(wmain));
tStart();
}
}
catch
{ }
finally
{ }
}
}
class work
{
public Socket mysock;
public TcpListener mylsn;
public void main()
{
//接收客户端消息
byte[] data = new byte[100];
mysockReceive(data);
string rt = SystemTextUTF8EncodingUTF8GetString(data);
ConsoleWriteLine(rt);
//给客户端发消息
mysockSend(UTF8EncodingUTF8GetBytes("server callback"));
//释放资源
mysockClose();
mylsnStop();
}
}
}
客户端代码:
[html] view plain copy
using System;
using SystemCollectionsGeneric;
using SystemLinq;
using SystemText;
using SystemNet;
using SystemNetSockets;
using SystemThreading;
using SystemIO;
namespace SockClient
{
class Program
{
public static void Main()
{
//新建客户端套接字
TcpClient tclient = new TcpClient();
//连接服务器
tclientConnect("127001", 8001);
ConsoleWriteLine("输入要发送的消息");
//读入要传输的字符
string str = ConsoleReadLine();
//得到流
Stream stm = tclientGetStream();
//发送字符串
ASCIIEncoding asen = new ASCIIEncoding();
byte[] data = asenGetBytes(str);
stmWrite(data, 0, dataLength);
//接受服务器返回的消息
byte[] back = new byte[100];
int k = stmRead(back, 0, 100);
//输出服务器返回的消息
for (int i = 0; i < k; i++)
{
ConsoleWrite(ConvertToChar(back[i]));
}
//关闭连接
tclientClose();
}
}
}
程序分Server和Client
服务器端打开侦听的端口,一有客户端连接就创建两个新的线程来负责这个连接
一个负责客户端发送的信息(ClientMsgCollectThread 类),
另一个负责通过该Socket发送数据(ServerMsgSendThread )
Serverjava代码如下:
/
创建日期 2009-3-7
TODO 要更改此生成的文件的模板,请转至
窗口 - 首选项 - Java - 代码样式 - 代码模板
/
package faueMutiUser;
import javaioBufferedReader;
import javaioIOException;
import javaioInputStreamReader;
import javaioPrintWriter;
import javanetServerSocket;
import javanetSocket;
/
服务器端
@author Faue
/
public class Server extends ServerSocket {
private static final int SERVER_PORT = 10000;
/
构造方法,用于实现连接的监听
@throws IOException
/
public Server() throws IOException {
super(SERVER_PORT);
try {
while (true) {
Socket socket = superaccept();
new Thread(new ClientMsgCollectThread(socket), "getAndShow"
+ socketgetPort())start();
new Thread(new ServerMsgSendThread(socket), "send"
+ socketgetPort())start();
}
} catch (IOException e) {
eprintStackTrace();
}
}
public static void main(String[] args) throws IOException {
new Server();
}
/
该类用于创建接收客户端发来的信息并显示的线程
@author Faue
@version 100
/
class ClientMsgCollectThread implements Runnable {
private Socket client;
private BufferedReader in;
private StringBuffer inputStringBuffer = new StringBuffer("Hello");
/
得到Socket的输入流
@param s
@throws IOException
/
public ClientMsgCollectThread(Socket s) throws IOException {
client = s;
in = new BufferedReader(new InputStreamReader(client
getInputStream(), "GBK"));
}
public void run() {
try {
while (!clientisClosed()) {
inputStringBufferdelete(0, inputStringBufferlength());
inputStringBufferappend(inreadLine());
Systemoutprintln(getMsg(inputStringBuffertoString()));
}
} catch (IOException e) {
//eprintStackTrace();
Systemoutprintln(clienttoString() + " is closed!");
}
}
/
构造显示的字符串
@param line
@return
/
private String getMsg(String line) {
return clienttoString() + " says:" + line;
}
}
/
该类用于创建发送数据的线程
@author Faue
@version 100
/
class ServerMsgSendThread implements Runnable {
private Socket client;
private PrintWriter out;
private BufferedReader keyboardInput;
private StringBuffer outputStringBuffer = new StringBuffer("Hello");
/
得到键盘的输入流
@param s
@throws IOException
/
public ServerMsgSendThread(Socket s) throws IOException {
client = s;
out = new PrintWriter(clientgetOutputStream(), true);
keyboardInput = new BufferedReader(new InputStreamReader(Systemin));
}
public void run() {
try {
while (!clientisClosed()) {
outputStringBufferdelete(0, outputStringBufferlength());
outputStringBufferappend(keyboardInputreadLine());
outprintln(outputStringBuffertoString());
}
} catch (IOException e) {
//eprintStackTrace();
Systemoutprintln(clienttoString() + " is closed!");
}
}
}
}
客户端:
实现基于IP地址的连接,连接后也创建两个线程来实现信息的发送和接收
/
创建日期 2009-3-7
/
package faueMutiUser;
import javaioBufferedReader;
import javaioIOException;
import javaioInputStreamReader;
import javaioPrintWriter;
import javanetSocket;
/
客户端
@author Faue
/
public class Client {
private Socket mySocket;
/
创建线程的构造方法
@param IP
@throws IOException
/
public Client(String IP) throws IOException {
try {
mySocket = new Socket(IP, 10000);
new Thread(new ServerMsgCollectThread(mySocket), "getAndShow"
+ mySocketgetPort())start();
new Thread(new ClientMsgSendThread(mySocket), "send"
+ mySocketgetPort())start();
} catch (IOException e) {
//eprintStackTrace();
Systemoutprintln("ServerIP:" + IP
+ " port:10000 can not be Connected");
}
}
public static void main(String[] args) throws IOException {
try {
new Client(args[0]);
} catch (Exception e) {
Systemoutprintln("输入的IP地址错误");
}
}
/
该类用于创建接收服务端发来的信息并显示的线程
@author Faue
@version 100
/
class ServerMsgCollectThread implements Runnable {
private Socket client;
private BufferedReader in;
private StringBuffer inputStringBuffer = new StringBuffer("Hello");
/
得到Socket的输入流
@param s
@throws IOException
/
public ServerMsgCollectThread(Socket s) throws IOException {
client = s;
in = new BufferedReader(new InputStreamReader(client
getInputStream(), "GBK"));
}
public void run() {
try {
while (!clientisClosed()) {
inputStringBufferdelete(0, inputStringBufferlength());
inputStringBufferappend(inreadLine());
Systemoutprintln(getMsg(inputStringBuffertoString()));
}
} catch (IOException e) {
//eprintStackTrace();
Systemoutprintln(clienttoString() + " is closed!");
Systemexit(0);
}
}
/
构造输入字符串
@param line
@return
/
private String getMsg(String line) {
return clienttoString() + " says:" + line;
}
}
/
该类用于创建发送数据的线程
@author Faue
@version 100
/
class ClientMsgSendThread implements Runnable {
private Socket client;
private PrintWriter out;
private BufferedReader keyboardInput;
private StringBuffer outputStringBuffer = new StringBuffer("Hello");
/
得到键盘的输入流
@param s
@throws IOException
/
public ClientMsgSendThread(Socket s) throws IOException {
client = s;
out = new PrintWriter(clientgetOutputStream(), true);
keyboardInput = new BufferedReader(new InputStreamReader(Systemin));
}
public void run() {
try {
while (!clientisClosed()) {
outputStringBufferdelete(0, outputStringBufferlength());
outputStringBufferappend(keyboardInputreadLine());
outprintln(outputStringBuffertoString());
}
outprintln("--- See you, bye! ---");
} catch (IOException e) {
//eprintStackTrace();
Systemoutprintln(clienttoString() + " is closed!");
Systemexit(0);
}
}
}
}
如果对您有帮助,请记得采纳为满意答案,谢谢!祝您生活愉快!
vaela
原理是这样的,服务器端有一个客户端管理器,负责管理所有连接进来的客户端,另外还需要为这个客户端管理器注册一个监听器,监听客户端的连接与断开两个动作,有客户端连接进来,就会触发监听器,监听器获取该客户端的在线好友列表,向在线的好友推送上线提醒消息,客户端断开时,也会出发监听器,监听器获取该客户端的在线好友列表,向在线的好友推送下线提醒消息
进程和线程是操作系统中的两个重要概念,本文将深入探讨它们的区别和联系。
0条评论