Network code with PostgreSQL DB Problem c# resolved
Posted: Tue Apr 25, 2006 4:41 am
I resolved this issue --
the problem was with the PostgreSQL OLEDB driver
it has a bug that causes it to NOT work within a thread!
the ODBC driver works GREAT! .. i found this info in the PostgreSQL forums so i changed my code over to use the ODBC driver and all is well
Just thought u guys should know if anyone is using postgres from a thread and is beating thier heads against thier monitor to no avail... use ODBC.
hey all,
i am pulling my hair out after working on this "threaded network server/client" code.
Anyone know about .net network or thread stuff?
I am new to thread programming so i suspect there are some limitations with thread programming that may not be in normal code? anyway here's what i am doing ..
I have a server that listens to a port .. my client connects to the server and it (the server) spawns a new thread to handle the connection.
I thought this might be a good way to handle clients as you are supposed to be able to handle many clients this way.
ok well any way all that code is working (i will post code in a minute)
so i have this code snippet that connects to my local PostgreSQL database, reads the players_loged_in field (this is just a test field for lack of a beter name) and prints them out to the console, closes the database and datareader and exits.
this code works fine by its self. but when i add a class or a function with the code, i fire it off over the network and it bombs out right after i define the data reader. here's the code, i hope someone can spot my problem as i been to close to the code for to long now to see it i am asuming.
here's the class that works along but not with the code.
using System;
using System.Data;
using System.Data.OleDb;
namespace server
{
public class database
{
public static void GetPlayerPass(string message)
{
string MyConnectString = "Provider=PostgreSQL;USER ID=postgres;PASSWORD=*******;Data Source=127.0.0.1;Extended Properties=;Location=game"; //commented out password
string mySelectQuery = "SELECT name FROM players_loged_in";
OleDbConnection myConnection = new OleDbConnection(MyConnectString);
OleDbCommand myCommand = new OleDbCommand(mySelectQuery, myConnection);
myConnection.Open();
OleDbDataReader myDataReader;
myDataReader = myCommand.ExecuteReader(); // ******* this is where the code bombs ****
while ( myDataReader.Read() )
{
try
{
Console.WriteLine(myDataReader.GetString(0));
}
catch {Console.WriteLine("no data available for your query");}
}
myDataReader.Close();
myConnection.Close();
}
}
}
and here is the rest of the server code that works great by itself by the way
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Collections;
using System.Data;
using System.Data.OleDb;
using server;
public class Player
{
public static string[] PlayerList = new string[350];//350 max connections
public static int PlayerListCounter=0;
//ArrayList PlayerList = new ArrayList();
public static void AddPlayer(string name)
{
PlayerList[PlayerListCounter] = name;
PlayerListCounter++;
}
public static void RemovePlayer(string name)
{
ArrayList myal = new ArrayList();
for (int i=0;i<PlayerListCounter;i++)
{myal.Add(PlayerList);} //copy PlayerList over to ArrayList
if (myal.Contains(name))
{
myal.Remove(name);
PlayerListCounter -=1;
for(int i=0;i<PlayerListCounter;i++)
{PlayerList = myal.ToString();}
}
}
}
class ThreadedTcpSrvr
{
private TcpListener client;
public ThreadedTcpSrvr()
{
client = new TcpListener(9050);
client.Start();
Console.WriteLine("Waiting for clients...");
while(true)
{
while (!client.Pending())
{
Thread.Sleep(1000);
}
ConnectionThread newconnection = new ConnectionThread();
newconnection.threadListener = this.client;
Thread newthread = new Thread(new
ThreadStart(newconnection.HandleConnection));
newthread.Start();
}
}//end TcpListener class
public static void Main()
{ database.GetPlayerPass("hello");
ThreadedTcpSrvr server = new ThreadedTcpSrvr();
}
}// ThreadedTcpSrvr
class ConnectionThread
{
public TcpListener threadListener;
private static int connections = 0;
public void HandleConnection()
{
int recv;
byte[] data = new byte[1024];
TcpClient client = threadListener.AcceptTcpClient();
NetworkStream ns = client.GetStream();
connections++;
string message = "Welcome To <need server name>";
Console.WriteLine("New client accepted: {0} active connections", connections);
data = Encoding.ASCII.GetBytes(message);
ns.Write(data, 0, data.Length);
//log player in
//get player ID
//make a player message queue
bool charlogin = true;
bool PlayerAuthUser = false;//user login in
bool PlayerAuthPass = false;//user entering pass
string PlayerName = null;
string PlayerPass = null; //holds player pass
//database PlayerDB = new database();
while(charlogin == true)
{
data = new byte[1024];
recv = ns.Read(data, 0, data.Length);
if (recv == 0)
break;
//Console.WriteLine(Encoding.ASCII.GetString(data));
message = Encoding.ASCII.GetString(data);
//trim the message down to the size of the data so we can parse and print them
message = message.Remove(recv,(1024 - recv));
if (PlayerAuthUser == false)
{ PlayerName = message;
database.GetPlayerPass(message);
PlayerAuthUser = true;
PlayerAuthPass = false;
}
if (PlayerAuthUser == true && PlayerAuthPass == false)
{
if(message == PlayerPass)
{
Player.AddPlayer(PlayerName);//add player to static list
Console.WriteLine("Player: {0} connected to world", PlayerName);
}
}
ns.Write(data, 0, recv);
}
ns.Close();
client.Close();
connections-=1;
Console.WriteLine("Client disconnected: {0} active connections", connections);
}//end HandleConnection
}//end ConnectionThread
//end MyServerClass
i have tried instantiation of the class like database PlayerDB = new database(); and all the other ways i can think of but i think the problem must be something else.
Thanks again for listening to my ramblings guys and i know my code isn't the best as far as "coding standards" so please be kind in your replies
the problem was with the PostgreSQL OLEDB driver
it has a bug that causes it to NOT work within a thread!
the ODBC driver works GREAT! .. i found this info in the PostgreSQL forums so i changed my code over to use the ODBC driver and all is well
Just thought u guys should know if anyone is using postgres from a thread and is beating thier heads against thier monitor to no avail... use ODBC.
hey all,
i am pulling my hair out after working on this "threaded network server/client" code.
Anyone know about .net network or thread stuff?
I am new to thread programming so i suspect there are some limitations with thread programming that may not be in normal code? anyway here's what i am doing ..
I have a server that listens to a port .. my client connects to the server and it (the server) spawns a new thread to handle the connection.
I thought this might be a good way to handle clients as you are supposed to be able to handle many clients this way.
ok well any way all that code is working (i will post code in a minute)
so i have this code snippet that connects to my local PostgreSQL database, reads the players_loged_in field (this is just a test field for lack of a beter name) and prints them out to the console, closes the database and datareader and exits.
this code works fine by its self. but when i add a class or a function with the code, i fire it off over the network and it bombs out right after i define the data reader. here's the code, i hope someone can spot my problem as i been to close to the code for to long now to see it i am asuming.
here's the class that works along but not with the code.
using System;
using System.Data;
using System.Data.OleDb;
namespace server
{
public class database
{
public static void GetPlayerPass(string message)
{
string MyConnectString = "Provider=PostgreSQL;USER ID=postgres;PASSWORD=*******;Data Source=127.0.0.1;Extended Properties=;Location=game"; //commented out password
string mySelectQuery = "SELECT name FROM players_loged_in";
OleDbConnection myConnection = new OleDbConnection(MyConnectString);
OleDbCommand myCommand = new OleDbCommand(mySelectQuery, myConnection);
myConnection.Open();
OleDbDataReader myDataReader;
myDataReader = myCommand.ExecuteReader(); // ******* this is where the code bombs ****
while ( myDataReader.Read() )
{
try
{
Console.WriteLine(myDataReader.GetString(0));
}
catch {Console.WriteLine("no data available for your query");}
}
myDataReader.Close();
myConnection.Close();
}
}
}
and here is the rest of the server code that works great by itself by the way
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Collections;
using System.Data;
using System.Data.OleDb;
using server;
public class Player
{
public static string[] PlayerList = new string[350];//350 max connections
public static int PlayerListCounter=0;
//ArrayList PlayerList = new ArrayList();
public static void AddPlayer(string name)
{
PlayerList[PlayerListCounter] = name;
PlayerListCounter++;
}
public static void RemovePlayer(string name)
{
ArrayList myal = new ArrayList();
for (int i=0;i<PlayerListCounter;i++)
{myal.Add(PlayerList);} //copy PlayerList over to ArrayList
if (myal.Contains(name))
{
myal.Remove(name);
PlayerListCounter -=1;
for(int i=0;i<PlayerListCounter;i++)
{PlayerList = myal.ToString();}
}
}
}
class ThreadedTcpSrvr
{
private TcpListener client;
public ThreadedTcpSrvr()
{
client = new TcpListener(9050);
client.Start();
Console.WriteLine("Waiting for clients...");
while(true)
{
while (!client.Pending())
{
Thread.Sleep(1000);
}
ConnectionThread newconnection = new ConnectionThread();
newconnection.threadListener = this.client;
Thread newthread = new Thread(new
ThreadStart(newconnection.HandleConnection));
newthread.Start();
}
}//end TcpListener class
public static void Main()
{ database.GetPlayerPass("hello");
ThreadedTcpSrvr server = new ThreadedTcpSrvr();
}
}// ThreadedTcpSrvr
class ConnectionThread
{
public TcpListener threadListener;
private static int connections = 0;
public void HandleConnection()
{
int recv;
byte[] data = new byte[1024];
TcpClient client = threadListener.AcceptTcpClient();
NetworkStream ns = client.GetStream();
connections++;
string message = "Welcome To <need server name>";
Console.WriteLine("New client accepted: {0} active connections", connections);
data = Encoding.ASCII.GetBytes(message);
ns.Write(data, 0, data.Length);
//log player in
//get player ID
//make a player message queue
bool charlogin = true;
bool PlayerAuthUser = false;//user login in
bool PlayerAuthPass = false;//user entering pass
string PlayerName = null;
string PlayerPass = null; //holds player pass
//database PlayerDB = new database();
while(charlogin == true)
{
data = new byte[1024];
recv = ns.Read(data, 0, data.Length);
if (recv == 0)
break;
//Console.WriteLine(Encoding.ASCII.GetString(data));
message = Encoding.ASCII.GetString(data);
//trim the message down to the size of the data so we can parse and print them
message = message.Remove(recv,(1024 - recv));
if (PlayerAuthUser == false)
{ PlayerName = message;
database.GetPlayerPass(message);
PlayerAuthUser = true;
PlayerAuthPass = false;
}
if (PlayerAuthUser == true && PlayerAuthPass == false)
{
if(message == PlayerPass)
{
Player.AddPlayer(PlayerName);//add player to static list
Console.WriteLine("Player: {0} connected to world", PlayerName);
}
}
ns.Write(data, 0, recv);
}
ns.Close();
client.Close();
connections-=1;
Console.WriteLine("Client disconnected: {0} active connections", connections);
}//end HandleConnection
}//end ConnectionThread
//end MyServerClass
i have tried instantiation of the class like database PlayerDB = new database(); and all the other ways i can think of but i think the problem must be something else.
Thanks again for listening to my ramblings guys and i know my code isn't the best as far as "coding standards" so please be kind in your replies