Date: 28 Sep 2001 01:36:26 -0700 From: tristan.braun@gmx.net (NuArb) Subject: IO::Socket && IO::Select Problem Message-Id: <3dae1176.0109280036.b6a7d90@posting.google.com> Hi all socket-developers, I tried to write a chat application. My client is a Java Applet and the server is written in PERL. The server is listening via IO::Socket on Port 2666. The server is blocking until someone has something to say or a new connection request. New requests will be accepted and added to IO::Select. The client tries to connect to the server and is starting a thread for listening on the socket. Both the java and the perl code works well with some (~10) WS opening the applet and I thougth it is on the time to stress the server. I created a MDI VB project and added a form with the InternetExplorer Control on it. Per default the Control navigates to my applet. I instanciated the page 30 times and the last instance could send a message. The same with 60. When I try 90 simultanious connections the connect sucedded for all. ALL can receive messages. BUT only the first ~60 Instances can send and the server receives the message. After closing any Instances the previously sended message will received by the server. The same result is when I startet the VB MDI on two NT boxes with each have 50 instances. And when try more than 127 connections + 1 listen my perlserver crashes. But in the worst case I will have ~800 users connecting to it ! Here is a snipet of the log I am generating: IP [fileno]: Message [IO::Select->Count()] ... 10.84.39.163[43]: Hello 10.84.39.163[67]: This is a test 10.84.39.163[5]: disconnected [121] 10.84.39.163[6]: disconnected [120] 10.84.39.163[7]: disconnected [119] 10.84.39.163[8]: disconnected [118] 10.84.39.163[9]: disconnected [117] 10.84.39.163[71]: Some other stuff sended previously 10.84.39.163[10]: disconnected [116] 10.84.39.163[11]: disconnected [115] 10.84.39.163[12]: disconnected [114] 10.84.39.163[13]: disconnected [113] 10.84.39.163[14]: disconnected [112] 10.84.39.163[72]: Some other stuff sended previously 10.84.39.163[74]: Some other stuff sended previously 10.84.39.163[75]: Whats up ? ... With netstat -a I receive the following lines: The client: TCP myClient:3292 0.0.0.0:0 LISTENING ... TCP myClient:3411 0.0.0.0:0 LISTENING TCP myClient:3292 myServer:2666 ESTABLISHED ... TCP myClient:3411 myServer:2666 ESTABLISHED The server: TCP myServer:2666 myClient:3292 ESTABLISHED ... TCP myServer:2666 myClient:3411 ESTABLISHED Here is the server: - Perl v5.6.1 Binary build 628 provided by ActiveState - Windows 2000 Server with IIS 5.0 use strict; use IO::Socket; use IO::Socket::INET; use IO::Select; use FileHandle; my $CHAT = new FileHandle; $SIG{"INT"} = sub { $CHAT->close; exit 0 }; # Listen-Socket erstellen, das auf eingehende Verbindungen wartet. my $listen = IO::Socket::INET->new(Proto => 'tcp', LocalPort => 2666, Listen => 256, Reuse => 1) or die $!; # Listen-Socket in die Select-Tasche stecken, die Anforderungen überwacht. my $select = IO::Select->new($listen); $CHAT->open(">>Chat.txt") || die "Kann die Protokolldatei nicht öffnen. $!\n"; $CHAT->autoflush; my @ready; my @lines; my %Colors = (); my %IP = (); sub cCol { return (substr("000" . (int(rand 170) + 30) ,-3)) } sub Debug { my($Text) = @_; print $Text; print $CHAT $Text; } # Warten bis was passiert. while(@ready = $select->can_read) { my $socket; for $socket (@ready) { # Neue Sockets binden. if($socket == $listen) { my $new = $listen->accept; $select->add($new) if $new; $new->send("000000000Willkommen\n" . join('',@lines)); $IP{$new->fileno} = join('.',unpack("CCCC", $new->peeraddr())); Debug ($IP{$new->fileno} . "[" . $new->fileno . "]: connected [" . $select->count() ."]\n"); if (not exists $Colors{$IP{$new->fileno}}) { $Colors{$IP{$new->fileno}} = cCol . cCol . cCol; } } else { # Nachricht vom Socket auslesen. Wenn nicht klappt, Socket schliessen. my $line=""; $socket->recv($line,200); if($line eq "") { Debug ($IP{$socket->fileno} . "[" . $socket->fileno . "]: disconnected [" . $select->count() ."]\n"); #$socket->fileno . ": disconnected\n"; delete $IP{$socket->fileno}; $select->remove($socket); $socket->close; } else { Debug ($IP{$socket->fileno} . "[" . $socket->fileno . "]: " . $line); $line = $Colors{$IP{$socket->fileno}} . $line; push @lines, $line; shift @lines if $#lines > 5; my $socket; # Nachricht an jeden senden. Wenns nicht klappt, Socket schliessen. for $socket ($select->handles) { next if($socket==$listen); $socket->send("$line") or do { print $socket->fileno . ": disconnected\n"; $select->remove($socket); $socket->close; }; } }; } } } 1; Here is the client: - Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1_01) - Windows NT 4.0 SP 6a import java.awt.*; import java.awt.event.*; import java.applet.Applet; import java.io.*; import java.net.*; public class hello extends java.applet.Applet { Font f = new Font("Tahoma", Font.BOLD,11); Socket socket = null; InputStreamReader isr = null; BufferedReader in = null; PrintWriter out = null; static int iWSize = 7; static int iSSize = 100; Speicher X = new Speicher(iSSize, iWSize); Label lblEingabe = new Label("Message :", Label.LEFT); TextField txtEingabe = new TextField(25); Button btnSend = new Button("Send"); Color back = new Color(255,255,240); Scrollbar sbv = new Scrollbar(); Scrollbar sbh = new Scrollbar(Scrollbar.HORIZONTAL,0,25,0,100); AdjustmentListener scroll = new AdjustmentListener() { public void adjustmentValueChanged(AdjustmentEvent e) { repaint(); } }; ActionListener sender = new ActionListener() { public void actionPerformed(ActionEvent e) { String sValue = new String(txtEingabe.getText()); if (sValue != "") { out.println(sValue); out.flush(); txtEingabe.setText(""); repaint(); } } }; Thread checker = new Thread() { public void run() { boolean OK = true; while (OK) { try { String Input; Input = in.readLine(); if (Input != null) { X.Add(Input); if (X.Count() > iWSize && X.Count() <= (iSSize - iWSize)) { sbv.setVisibleAmount(100 - X.Count() + iWSize); sbv.setValue(sbv.getValue() + 1); } repaint(); } } catch (Exception e) { X.Add(e.getMessage()); OK = false; try { socket.close(); } catch (IOException ee) { X.Add(ee.getMessage()); } } } } }; public void init() { setLayout(null); setBackground(back); setFont(f); lblEingabe.setBounds(5,5,60,20); add(lblEingabe); txtEingabe.addActionListener(sender); txtEingabe.setBounds(65,5,210,20); add(txtEingabe); btnSend.addActionListener(sender); btnSend.setBounds(280,5,60,20); add(btnSend); sbv.addAdjustmentListener(scroll); sbv.setBounds(330,25,10,115); sbv.setVisibleAmount(100); add(sbv); sbh.addAdjustmentListener(scroll); sbh.setBounds(5,140,325,10); add(sbh); try { socket = new Socket(getDocumentBase().getHost(),2666); isr = new InputStreamReader(socket.getInputStream()); in = new BufferedReader(isr); out = new PrintWriter(socket.getOutputStream(), true); checker.start(); } catch (IOException e) { X.Add(e.getMessage()); } catch (SecurityException se) { X.Add(se.getMessage()); } } public void paint(Graphics screen) { screen.setFont(f); X.Rewind(iWSize + (iSSize - sbv.getVisibleAmount() - sbv.getValue())); int i = 0; do { screen.setColor(X.Col()); screen.drawString(X.Get(sbh.getValue()), 5, 40 + 15 * i++); } while (X.Next()); } public void stop() { try { socket.close(); } catch (IOException ee) { X.Add(ee.getMessage()); repaint(); } } class Speicher { //This is only the interface of a class simular to a stack public Color Col() public Speicher(int SSize, int VSize) public void Add(String Text) public String Get(int iStart) public int Count() public int getCursor() public int Pos() public void Rewind(int Laenge) public boolean Next() }; }; At least the VB MDI: - Visual Basic 6.0 (SP4) - Windows NT 4.0 SP 6a Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Private Sub MDIForm_Activate() Dim x(1 To 60) As Form1 Dim a As Integer Dim b As Integer For a = 1 To 60 Set x(a) = New Form1 x(a).Left = ((a - 1) Mod 3) * 4400 x(a).Top = Round((a - 2) / 3, 0) * 3100 x(a).Show x(a).WebBrowser1.Navigate "http://myServer/Java/Applet.htm" DoEvents Sleep 100 DoEvents Next End Sub Thanks in advance ! Regards, Tristan