For some reason, I have to enter something twice for it to print out in Java when Using Scanner in a thread. I dont know why this is, but IT is very annoying. Because of this, My message sends through the socket and gets to the other person but does not show it to the person sending it, but on the second try it shows to the person who sent it but it doesnt get to the person that should receive it!
(If something doesnt look like its from the Java API, its because its a Test Class for My API)
Note: The code is the exact same on both sides, except they use different ports.
private static UDPSocket TestUDP;
private static String Username = "9843";
public static void main(String[] args) {
try {
TestUDP = new UDPSocket(9844);
TestUDP.defineDefaultAddress("localhost", 9843);
Username = "Lawton";
System.out.println("You set your name to: " + Username);
new Thread(new Receive()).start();
new Thread(new Send()).start();
} catch (Exception e) {
e.printStackTrace();
}
}
static class Send implements Runnable {
public void run() {
try {
while (true) {
Scanner UserInput = new Scanner(System.in);
TestUDP.send("0x00", Username + ": " + UserInput.nextLine());
System.out.println(Username + ": " + UserInput.nextLine());
Thread.sleep(1);
}
} catch (Exception E) {
System.err.println("There was a error.");
}
}
}
static class Receive implements Runnable {
public void run() {
try {
while (true) {
byte[] Message = TestUDP.receive();
System.out.println(Packet.decrypt(Message));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Use a variable to avoid calling scanner.nextLine() twice:
Scanner UserInput = new Scanner(System.in);
String readUsername = UserInput.nextLine();
TestUDP.send("0x00", Username + ": " + readUsername);
System.out.println(Username + ": " + readUsername);
Related
I have a program that starts by creating a GUI to handle user input and display the output.
The first thing that happens is the window is created and then the Functions Class method initServer() is called to initialize some variables for the input and output portion
private JFrame frame;
public static Functions func = new Functions();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
Thread.currentThread().setName("Console");
System.out.println(Thread.currentThread().getName() + " [" + Thread.currentThread().getId() + "] Started");
try {
Console window = new Console();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
func.initServer();
}
});
}
With the Functions Class method initServer() being called, We start the process then follow by initializing the i/o variable that will handle all the streams being used to communicate with the process. Then we start the two threads - ConsoleInputWriter and ConsoleOutputReader - responsible for handling Input and Output to the process.
public class Functions {
private ConsoleOutputReader cor = new ConsoleOutputReader();
private ConsoleInputWriter ciw = new ConsoleInputWriter();
private OutputStreamWriter osw;
private InputStreamReader isr;
private BufferedWriter bw;
private BufferedReader br;
private BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
private File serverJar;
private String serverPath;
private ProcessBuilder builder;
private Process proc;
private boolean init = false;
public void initServer()
{
updateConsole("Server Initiated Status: " + serverStatus());
builder = new ProcessBuilder("/bin/bash");
try {
proc = builder.start();
} catch (IOException e) {
e.printStackTrace();
}
osw = new OutputStreamWriter(proc.getOutputStream());
bw = new BufferedWriter(osw);
isr = new InputStreamReader(proc.getInputStream());
br = new BufferedReader(isr);
serverStatus(true);
updateConsole("Server Initiated Status: " + serverStatus());
cor.start();
ciw.start();
}
public String recieveInput()
{
String s = null;
try {
s = input.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return s;
}
public boolean serverStatus()
{
return init;
}
public void serverStatus(boolean status)
{
init = status;
}
public void exec(String cmd)
{
try {
bw.write(cmd);
bw.newLine();
bw.flush();
} catch (IOException e) {
updateConsole("Cant run: [" + cmd + "] :::::::: " + e);
e.printStackTrace();
}
}
public void updateConsole()
{
//edit to print to textPane
try {
System.out.println(br.readLine());
} catch (IOException e) {
}
}
public void updateConsole(String s)
{
System.out.println(s);
}
public File getJar(/**String s**/)
{
serverJar = new File(Functions.class.
getResource("CraftBukkit.jar").getPath());
return serverJar;
}
public void setPath(String s)
{
serverPath = s;
}
public String getPath()
{
return serverPath;
}
}
Once called the Class ConsoleOutputReader starts and executes a command for the process to start a Jar File and confirms that the i/o streams have been initialized before it tries to get any output. If it continues to the while loop we should be getting output.
public class ConsoleOutputReader extends Thread{
private static Functions func = new Functions();
public void run()
{
currentThread().setName("cor");
System.out.println(currentThread().getName() + " [" + Thread.currentThread().getId() + "] Started");
func.exec("cd " + "~/Desktop/Bukkit" + " && java -Xmx1024M -jar " + func.getJar() + " -o true");
while(func.serverStatus())
func.updateConsole();
}
}
and the Class ConsoleInputWriter follows right after ConsoleOutputReader also confirming that the serverInit() boolean is true, then to wait in a while loop for an input from the user.
public class ConsoleInputWriter extends Thread{
public static Functions func = new Functions();
public void run()
{
currentThread().setName("ciw");
func.updateConsole(currentThread().getName() + " [" + Thread.currentThread().getId() + "] Started");
while(func.serverStatus())
func.exec(func.recieveInput());
}
}
The main issue I have is that with minimal knowledge on threads I seemed to have made the serverStatus() boolean from the Functions class equal two different things. where the output from ConsoleOutputReader is true and the output from ConsoleInputWriter is false. How would I make sure that when I start both threads they're seeing the same value when they call the method?
I've gotten this code to work with two threads where the main thread ran the inputs and a second thread was used to run the outputs, but I wanted to try it setup like this.
Any tips to my style and or patterns I use are also very welcome.
Edit: I realized with all my frantic changes that whatever class calls initServer() is that class that get true when they call serverStatus().
Any methods that change an object for both threads need to be synchronized. When the method runs, if the object is being read by one or both of the threads while it changes, The threads could read different values.
e.x.:
public static synchronized void initServer(boolean bool) { init = bool; }
I am writing a java program that will need to run a python script.
The script will print output which will java need to read to know the progress of the script.
To be able to pause the script while running I want it to ask for input once in a while, only when java give it input the script will keep going.
Here is my Java method:
private static void sevenTry(String[] strCommands) throws IOException {
Object oLock1 = new Object();
Object oLock2 = new Object();
ProcessBuilder pBuilder = new ProcessBuilder(strCommands);
pBuilder.redirectErrorStream(true);
Process proc = pBuilder.start();
Thread tReader = new Thread() {
#Override
public void run() {
System.out.println("~~tReader starting~~");
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
synchronized (oLock1) {
try {
String line = reader.readLine();
while (line != null && !line.trim().equals("--EOF--")) {
System.out.println("Stdout: " + line);
if (line.trim().equals("--INPUT--")) {
synchronized (oLock2) {
oLock2.notify();
}
oLock1.wait();
}
line = reader.readLine();
}
} catch (IOException e) {
System.out.println("tReader: " + e.getMessage());
} catch (InterruptedException e) {
System.out.println("tReader: " + e.getMessage());
} catch (Exception e) {
System.out.println("tReader: " + e.getMessage());
}
}
System.out.println("~~tReader end~~");
synchronized (oLock2) {
oLock2.notify();
}
}
};
Thread tWriter = new Thread() {
#Override
public void run() {
System.out.println("~~tWriter starting~~");
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(proc.getOutputStream()));
String line, input;
Scanner scan = new Scanner(System.in);
synchronized (oLock2) {
try {
oLock2.wait();
} catch (InterruptedException e1) {
System.out.println("tWriter: " + e1.getMessage());
}
}
while (tReader.isAlive()) {
synchronized (oLock1) {
System.out.println("Java: insert input");
scan.hasNext();
input = scan.nextLine();
try {
writer.write(input + "\n");
writer.flush();
} catch (IOException e) {
System.out.println("tWriter: " + e.getMessage());
}
oLock1.notify();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e1) {
System.out.println("tWriter: " + e1.getMessage());
}
}
System.out.println("~~tWriter end~~");
}
};
tReader.start();
tWriter.start();
System.out.println("~~everything submitted~~");
try {
tReader.join();
tWriter.join();
System.out.println("~~finish~~");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
This is my python script:
# coding=utf-8
import sys
print '1'
print '--INPUT--'
inum = sys.stdin.readline()
print '2'
print '--EOF--'
I tried running my code
sevenTry("python", "C:\\Testing.py");
but on java side it get stuck inside tReader at line:
String line = reader.readLine();
The program does work if i take out the input line from the python file
inum = sys.stdin.readline()
Using
inum = raw_input()
still bring up the same problem (im using python 2.7)
The most confusing part here that i even tried to test this with a java file (instead of python)
sevenTry("java", "-classpath", "C:\\class", "CheckCMD");
and it worked even with the input lines
import java.util.Scanner;
public class CheckCMD {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String line;
System.out.println("1");
System.out.println("--INPUT--");
in.hasNext();
line = in.nextLine();
System.out.println("2");
System.out.println("--EOF--");
}
}
As you may have noticed, this is a problem related to Python.
As described in https://unix.stackexchange.com/questions/182537/write-python-stdout-to-file-immediately,
" when process STDOUT is redirected to something other than a terminal, then the output is buffered into some OS-specific-sized buffer (perhaps 4k or 8k in many cases)."
So, you need to call sys.stdout.flush() after each invoke to print.
Or, as a better option, you can change the default behaviour for the process, using the -u param, to get unbuffered output.
I made a ReadMessage thread that should run in the background and read messages when they come in. This is how it looks:
Thread ReadMessages = new Thread(new Runnable() {
public void run() {
try {
while(socket.isConnected()){
ServerMsg = in.readLine();
jTextArea1.append(ServerMsg);
}
} catch (IOException ex) {
System.out.println("Something went wrong! THREAD");
}
}
});
I start it everytime i start my program:
public TwitchBotFenster() throws IOException, Exception {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
initComponents();
ReadMessages.start();
}
The problem I have, is that it only reads the first messages when I connect to twitch irc but if I write something in the chat it doesnt. I dont really get the problem. My thoughts when I made that were, whenever the socket is connected it should read all the messages.
EDIT:
This is how i send messages to the server:
public void SendMessage() throws IOException{
try{
if(BotName == null){
this.jTextArea1.append("You are not logged in!\n");
}else{
this.ClientChatMessage = this.jTextField4.getText();
out.write(":" + BotName + "!" + BotName + "#" + BotName + ".tmi.twitch.tv PRIVMSG #" + this.Channelname + " :" + this.ClientChatMessage + "\n");
out.flush();
this.jTextField4.setText("");
this.jTextArea1.append("*" + BotName + ">> " + ClientChatMessage + "\n");
}
this.jTextField4.setText("");
}catch(Exception exe){
System.out.println("Something went horribly wrong! (SendMessage/func)\n");
}
}
EDIT2:
Messages are sent whenever i press enter in my jTextField:
private void jTextField4ActionPerformed(java.awt.event.ActionEvent evt) {
try {
SendMessage();
} catch (IOException ex) {
System.out.println("Something went horribly wrong! (SendMessage)\n");
}
}
I have problem with my multhreaded server for bridge auction. The topic of it is less important, all I need to do so far is to make the loop inside the run method work for more than only one "lap". I mean my loop is working for each client only once and then It stopped, but I can't solve this problem. It should work all the time and after sequence of players N-> E-> S-> W-> it start another lap from player N, but now it just stand still...
Check my code:
package serwer;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.logging.*;
public class Serwer {
public static void main(String[] args) throws Exception {
System.out.println("Started server to the bridge auction");
int conCount = 0;
ServerSocket serwer = new ServerSocket(9898);
ArrayList<connection> connections = new ArrayList<connection>(){};
try {
//only 4 players are allowed to play bridge in one table
while (connections.size() < 4) {
connection p = new connection(serwer.accept(), conCount++);
connections.add(p);
connections.get(conCount-1).start();
}
} finally {
serwer.close();
}
}
/**
* static class responsible for the connection in multithreaded server
*/
static class connection extends Thread {
private Socket socket;
private int conCount;
private static int counter = 0;
private final String[] Players;
private String stringOnServer = "0";
private int stake = 1;
public connection(Socket socket, int conCount) {
this.Players = new String[]{"N", "E", "S", "W"};
this.socket = socket;
this.conCount = conCount;
System.out.println("New connection id: " + Players[conCount]);
}
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
//here is info what player are you
out.println("You are player on position " + Players[conCount]);
while (true) {
synchronized (this) {
if (counter % 4 == conCount) {
while (true) {
out.println("Your turn " + Players[conCount] + ", please input the text: ");
String input = in.readLine();
System.out.println("\t" + Players[conCount] + " : " + input);
counter += 1;
//for now only the stringOnServer is simply echo
stringOnServer = input;
System.out.println("\tCurrent string on server = " + stringOnServer);
try {
this.wait();
} catch (InterruptedException ex) {
Logger.getLogger(Serwer.class.getName()).log(Level.SEVERE, null, ex);
}
break;
}
} else {
this.notify();
}
}
}
} catch (IOException e) {
System.out.println("error with player: " + Players[conCount] + ": " + e);
} finally {
try {
socket.close();
} catch (IOException e) {
System.out.println("can't closed");
}
System.out.println("connection with player" + Players[conCount] + " terminated");
}
}
}
}
Client's code is really simple, but if someone will have time and patience to test it I add it to:
package klient;
import java.net.*;
import java.io.*;
public class Klient {
public static void main(String[] args) throws IOException {
try {
Socket s = new Socket("127.0.0.1", 9898);
String answer;
System.out.println("Welcome on the server of auction.");
//Here is displayed info from server what player are you
BufferedReader fromServer = new BufferedReader(new InputStreamReader(s.getInputStream()));
System.out.println(fromServer.readLine());
while (true) {
System.out.println(fromServer.readLine());
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
answer = input.readLine();
out.println(answer);
}
} catch (ConnectException ex) {
System.out.println("There are 4 players on server or server is closed, try again later");
}
}
}
The problem is in this loop in connection class with counter.
Thanks in advance for your help :)
You have to call notify() from another thread. Your current thread is waiting and cannot notify itself.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
well, what i want to do is basically, to make a client server chat program that works over internet, ive done a basic one that works flawlessly over lan, but cant get it right over the internet..
Server :
public class Server extends javax.swing.JFrame {
HashMap<String,PrintWriter> map = new HashMap<String,PrintWriter>();
ArrayList clientOutputStreams = new ArrayList();
ArrayList<String> onlineUsers = new ArrayList();
int port = 5080;
Socket clientSock = null;
public class ClientHandler implements Runnable {
BufferedReader reader;
Socket sock;
PrintWriter client;
public ClientHandler(Socket clientSocket, PrintWriter user) {
// new inputStreamReader and then add it to a BufferedReader
client = user;
try {
sock = clientSocket;
InputStreamReader isReader = new InputStreamReader(sock.getInputStream());
reader = new BufferedReader(isReader);
System.out.println("first");
} // end try
catch (Exception ex) {
System.out.println("error beginning StreamReader");
} // end catch
} // end ClientHandler()
#Override
public void run() {
System.out.println("run method is running");
String message;
String[] data;
String connect = "Connect";
String disconnect = "Disconnect";
String chat = "Chat";
try {
while ((message = reader.readLine()) != null) {
ta1.append(message + "\n");
ta1.repaint();
System.out.println("Received: " + message);
data = message.split("#");
for (String token : data) {
System.out.println(token);
}
System.out.println(data[data.length - 1] + " datalast");
if (data[2].equals(connect)) {
tellEveryone((data[0] + "#" + data[1] + "#" + chat));
userAdd(data[0]);
map.put(data[0], client);
} else if (data[2].equals(disconnect)) {
System.out.println("barpppppppppp");
tellEveryone((data[0] + "#has disconnected." + "#" + chat));
userRemove(data[0]);
map.remove(data[0]);
} else if (data[2].equals(chat)) {
tellEveryone(message);
} else {
System.out.println("No Conditions were met.");
}
} // end while
} // end try
catch (Exception ex) {
System.out.println("lost a connection");
System.out.println(ex.getMessage());
clientOutputStreams.remove(client);
} // end catch
} // end run()
}
public void go() {
// clientOutputStreams = new ArrayList();
try {
ServerSocket serverSock = new ServerSocket(port);
System.out.println("ServerSocket Created !");
System.out.println("Started listening to port " + port);
while (true) {
// set up the server writer function and then begin at the same
// the listener using the Runnable and Thread
clientSock = serverSock.accept();
PrintWriter writer = new PrintWriter(clientSock.getOutputStream());
ta1.append(writer + " ");
ta1.repaint();
System.out.println(writer);
clientOutputStreams.add(writer);
//data_of_names_and_output_streams.add(writer.toString());
// use a Runnable to start a 'second main method that will run
// the listener
Thread listener = new Thread(new Server.ClientHandler(clientSock, writer));
listener.start();
System.out.println("Server Thread for 'new player' was started");
System.out.println("got a connection");
} // end while
} // end try
catch (Exception ex) {
System.out.println("error making a connection");
} // end catch
} // end go()
public void userAdd(String data) {
String message;
String add = "# #Connect", done = "Server# #Done";
onlineUsers.add(data);
String[] tempList = new String[(onlineUsers.size())];
onlineUsers.toArray(tempList);
for (String token : tempList) {
message = (token + add);
tellEveryone(message);
System.out.println(message);
}
tellEveryone(done);
}
public void userRemove(String data) {
System.out.println(onlineUsers.size() + " is size of online users");
System.out.println(clientOutputStreams.size() + " is size of ous");
String message;
String add = "# #Connect", done = "Server# #Done";
onlineUsers.remove(data);
String[] tempList = new String[(onlineUsers.size())];
onlineUsers.toArray(tempList);
for (String token : tempList) {
message = (token + add);
tellEveryone(message);
}
tellEveryone(done);
}
public void tellEveryone(String message) {
System.out.println(onlineUsers.size() + " is size of online users");
System.out.println(clientOutputStreams.size() + " is size of ous");
// jButton1.doClick();
// sends message to everyone connected to server
Iterator it = clientOutputStreams.iterator();
if (message.length() < 250) {
System.out.println("inside it");
while (it.hasNext()) {
try {
PrintWriter writer = (PrintWriter) it.next();
writer.println(message);
// l1.setText(message);
System.out.println("Sending " + message);
writer.flush();
} // end try
catch (Exception ex) {
System.out.println("error telling everyone");
} // end catch
}
} else {
try {
clientSock.close();
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
/**
* Creates new form Server
*/
public Server() {
initComponents();
ta1.repaint();
}
public static void main(String args[]) throws Exception {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Server().setVisible(true);
}
});
new Server().go();
}
} //end form
Client : jbutton1 is setting up connection,jbutton2 sends the message.
public class Client extends javax.swing.JFrame {
boolean sent, receive;
SimpleDateFormat sdf;
String ip;
String username;
Socket sock;
BufferedReader reader;
PrintWriter writer;
ArrayList<String> userList = new ArrayList();
Boolean isConnected = false;
DefaultListModel dlm;
public Client() {
initComponents();
dlm = (DefaultListModel) l1.getModel();
ip = JOptionPane.showInputDialog("Enter the IP of the server to connect");
}
public class IncomingReader implements Runnable {
public void run() {
String stream;
String[] data;
String done = "Done", connect = "Connect", disconnect = "Disconnect", chat = "Chat", battlerequest = "battlerequest";
try {
while ((stream = reader.readLine()) != null) {
data = stream.split("#");
System.out.println(stream + " ------------------------ data");
if (data[2].equals(chat)) {
sdf = new SimpleDateFormat("HH:mm:ss");
t.append("(" + sdf.format(new Date()) + ") " + data[0] + ": " + data[1] + "\n");
//t.setText("<html><b>hi" + 3 + 3 + "</b></html>");
} else if (data[2].equals(connect)) {
t.removeAll();
userAdd(data[0]);
} else if (data[2].equals(disconnect)) {
userRemove(data[0]);
} else if (data[2].equals(done)) {
dlm.removeAllElements();
writeUsers();
userList.clear();
} else {
System.out.println("no condition met - " + stream);
}
}
} catch (Exception ex) {
System.out.println(ex.getMessage() + " hi");
}
}
}
public void ListenThread() {
Thread IncomingReader = new Thread(new Client.IncomingReader());
IncomingReader.start();
}
public void userAdd(String data) {
userList.add(data);
}
public void userRemove(String data) {
t.setText(t1.getText() + data + " has disconnected.\n");
}
public void writeUsers() {
String[] tempList = new String[(userList.size())];
userList.toArray(tempList);
for (String token : tempList) {
//ul.append( token + "\n");
dlm.addElement(token);
// ul.setText(ul.getText() + token + '\n');
}
}
public void sendDisconnect() {
String bye = (username + "# #Disconnect");
try {
writer.println(bye); // Sends server the disconnect signal.
writer.flush(); // flushes the buffer
} catch (Exception e) {
t.append("Could not send Disconnect message.\n");
}
}
public void Disconnect() {
try {
t.append("Disconnected.\n");
sock.close();
} catch (Exception ex) {
t.append("Failed to disconnect. \n");
}
isConnected = false;
n.setEditable(true);
dlm.removeAllElements();
// ul.setText("");
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
if (isConnected == false && !n.getText().equals("")) {
username = n.getText();
n.setEditable(false);
try {
sock = new Socket(ip, 5080);
InputStreamReader streamreader = new InputStreamReader(sock.getInputStream());
reader = new BufferedReader(streamreader);
writer = new PrintWriter(sock.getOutputStream());
writer.println(username + "#has connected.#Connect"); // Displays to everyone that user connected.
writer.flush(); // flushes the buffer
isConnected = true;
jLabel4.setText(n.getText());
//t.append( "<html><font color = \"black\"><b>Server : Welcome,</b></font></html>"+username);
//t1.setText("<html><font color=\"red\">yo</font></html>");
// Used to see if the client is connected.
} catch (Exception ex) {
t.append("Cannot Connect! Try Again. \n");
n.setEditable(true);
}
ListenThread();
} else if (isConnected == true) {
t.append("You are already connected. \n");
} else if (n.getText().equals("")) {
t.append("Enter a valid name \n");
}
}
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
String nothing = "";
if ((t1.getText()).equals(nothing)) {
t1.setText("");
t1.requestFocus();
} else {
try {
writer.println(username + "#" + t1.getText() + "#" + "Chat");
writer.flush(); // flushes the buffer
} catch (Exception ex) {
t.append("Message was not sent. \n");
}
t1.setText("");
t1.requestFocus();
}
t1.setText("");
t1.requestFocus(); // TODO add your handling code here:
}
private void dicsActionPerformed(java.awt.event.ActionEvent evt) {
sendDisconnect();
Disconnect(); // TODO add your handling code here:
}
i have also port forwarded the ports i am going to use - ie. 5080
now when my friend opens the client program from his computer from his home, i tell him to enter the ip as 192.168.1.2 coz thats what is saved when i open cmd and type ipconfig....
sometimes i think that the ip address i gave him is wrong coz 192.168.1.2 is i guess lan or internal ip address, so then, so do i do ? where do i get the correct ip address ? or is something else wrong in my code ?
192.168.1.2 is a non-routable IP. Click here to get your current external IP (unless your IP address is static, it may change periodically).
If you were to sign up for a dynamic dns service (here for example), then you could give your friend a "domain name" (e.g. something.dnsdynamic.com) and the service would update when your IP address changes.