このブログを検索

2020/02/15

python3のcgiでpostgresqlのデータを参照する @CentOS8

pythonからpostgresqlを使うためのライブラリとして psycopg2というものがよく使われているようである。 

エラーが出ては足りないものをインストールした結果、 以下が必要であった。
dnf install postgresql-devel
dnf install gcc
dnf install python3-devel
pip install psycopg2

pythonでcgiが動くことはすでに確認済み。 
OSはCentOS8、pythonは3.6.8である。 

以下がpostgresqlのDBに登録されている内容を表示するcgiの例である。 

ローカル(cgiを実行しているサーバ)にある、 
monqy というデータベースの、 usersというテーブルに登録されているレコードの、 nameという項目の内容を、すべて表示する。
   
#!/usr/bin/python

import cgi
import psycopg2
import psycopg2.extras
import os

path = "localhost"
port = "5432"
dbname = "monqy"
user = "postgres"
password = "hogehoge"

pg_params = "host={} port={} dbname={} user={} password={}"
pg_params = pg_params.format(path,port,dbname,user,password)

sql = """select * from users"""

print('Content-Type: text/html; charset=utf-8')
print('')
print('')

connection = psycopg2.connect(pg_params)
cur = connection.cursor(cursor_factory=psycopg2.extras.DictCursor)
cur.execute(sql)

results = cur.fetchall()
for row in results:
        print(row['name'])
        print("
") cur.close connection.close print("")
この例ではDBの内容を辞書形式で取得することによって、項目名で値を取り出している。 

せっかくDBを使っているのに名前を使わないなんてわざわざライブラリを使う意味がないだろうから辞書形式で取得するのは必須だろう。

postgresqlをインストールしテーブルにデータを登録するまで(postgresql on CentOS8)

インストール

# dnf install postgresql

サーバーをインストール

# dnf install postgresql-server


初期化

# postgresql-setup initdb


設定ファイル変更
# cd /var/lib/pgsql/data/

デフォルト設定をバックアップ
# cp postgresql.conf postgresql.conf.org

# vi /var/lib/pgsql/data/postgresql.conf

最後の行に1行追加

  ....
  # CUSTOMIZED OPTIONS
  #------------------------------------------------------------------------------
  # Add settings for extensions here
  listen_addresses = '*'


もう一個設定ファイル変更

# cd ../data
# pwd
/var/lib/pgsql/data

# cp pg_hba.conf pg_hba.conf.org
# vi pg_hba.conf

以下のように変更
# cat pg_hba.conf

  # PostgreSQL Client Authentication Configuration File
  # ===================================================
 local   all     all                     trust
  host    all     all     127.0.0.1/32    trust
  host    all     all     ::1/128         trust




postgresqlを再起動

# systemctl restart postgresql

active(running) になる。

# systemctl status postgresql

● postgresql.service - PostgreSQL database server

   Loaded: loaded (/usr/lib/systemd/system/postgresql.service; disabled; vendor preset: disabled)

   Active: active (running) since Sat 2020-02-15 13:58:56 JST; 1s ago

  Process: 14332 ExecStartPre=/usr/libexec/postgresql-check-db-dir postgresql (code=exited, status=0/SUCCESS)
(以下略)


接続

# psql -U postgres -h 127.0.0.1 -w
psql (10.6)
Type "help" for help.

postgres=#

^Zで抜ける


パスワード変更

# psql -U postgres -c "ALTER ROLE postgres WITH PASSWORD 'hogehoge'"
ALTER ROLE

データベース作成


#psql -U postgres -W -c "CREATE DATABASE my_db";
Password for user postgres:

CREATE DATABASE

データベースを指定して接続

psql -U postgres my_db
my_db=#

Users というテーブルを作る

my_db=# create table Users (
my_db(#   userid         char(032)     primary key,
my_db(#   fullname       char(100),
my_db(#   phonenum       char(11),
my_db(#   postal         char(7),
my_db(#   created        timestamp,
my_db(# active boolean);
CREATE TABLE

my_db=#

確認

my_db=# \d
         List of relations
 Schema | Name  | Type  |  Owner
--------+-------+-------+----------
 public | users | table | postgres

(1 row)



テーブル定義を表示



my_db=# \d Users

                          Table "public.users"
  Column  |            Type             | Collation | Nullable | Default
----------+-----------------------------+-----------+----------+---------
 userid   | character(32)               |           | not null |
 fullname | character(100)              |           |          |
 phonenum | character(11)               |           |          |
 postal   | character(7)                |           |          |
 created  | timestamp without time zone |           |          |
 active   | boolean                     |           |          |
Indexes:
    "users_pkey" PRIMARY KEY, btree (userid)


テーブルにレコードを追加

my_db=# INSERT INTO Users(userid,fullname,created) VALUES ('john','John Lennon', current_timestamp);

INSERT 0 1

my_db=# INSERT INTO Users(userid,fullname,created) VALUES ('paul','Paul McCartney', current_timestamp);

INSERT 0 1


テーブルのレコードを表示



my_db=# select * from Users;

   userid   |   fullname      | phonenum | postal |     created                | active
------------+-----------------+----------+--------+----------------------------+--------
 John       | John Lennon     |          |        | 2020-02-15 14:23:36.832459 |
 monqy      | Paul McCartney  |          |        | 2020-02-15 14:23:53.176765 |
(2 rows)


※実際は項目長の長さだけ表示されるので折り返して汚くなったが上記は見やすく整形してある。



とりあえず一つのテーブルが作成できた。

今度はこのDBの内容をCGIで表示してみる。
そして登録、修正、削除ができるようにする。

systemctl status を実行したら degrated と表示された @CentOS7

CentOS7の話

以前さくらのVPSでmysqlをインストールしてちょっと使ってみたことがあったのだが、
久しぶりにDBをいじってみたいと思い、mysqlが起動しているか確認するために

systemctl status

を実行したら、赤字で

State: degrated

と表示された。


うわ!と思い、検索すると起動に失敗したサービスがある場合にそうなるらしいことがわかった。

きっと使ってないしょうもないサービスだろうから無効にしようと思い、

systemctl --failed

を実行すると

● firewalld.service loaded failed failed firewalld - dynamic firewall daemon


firewalldが起動していなかった。

さすがにそれはマズいだろうとちょっと焦ってなんでだろうと調べた結果思い当たったのは、しばらく前にpythonのシンボリックリンクを3系向けに変更したことだった。

それを変更したのはpythonで書いたcgiが動かなくなったからだったのだが、
firewallが起動しないことの方が問題なのでとりあえずシンボリックリンクを2系向けに戻した。

firewalldは起動するようになり、cgiはエラーになった。

cgiの1行目(これなんて言うんだっけ)を

#!/bin/python3.6

に直す。

これでcgiも動くようになった。

pythonのデフォルトバージョンが2系になってしまったが、
コマンドでpythonを実行することはあまりないのでいいか.....

それにしてもpythonの2系・3系問題はウザいね.....

CentOS8はみんなpython3系になっているようなのでこういうことは起こらないみたい。

で、本来確認したかったmysqlは動いてなかった。

ある暴露話について感じたこと

twitterであるプロジェクトの暴露話が話題になった。

それに関して感じたことを書いておきたい。

どこまで本当の話かわからないし、ブログの筆者、かれが非難している「PM」なる人に対して批判や反論をしたいわけではないので、リンク等は一切貼らない。

暴露した人は結局耐え切れずにプロジェクトを抜けており、
一方的にプロジェクトを、そしてその「PM」を非難しているので、
どこまで信用できるかわからないが、それほど事実とことなる話ではなさそうに感じた。

同情する点、自分も反省しないとと思わされた点もあったが、彼の言い分に同意できない部分もあった。

この話で完全に否定されている「PM」と呼ばれている人物が誰なのかとても知りたくて、
この話にまつわるtweetを読み漁り特定のキーワードで検索した結果、誰なのか(twitterのアカウント)がわかった。

けっこう有名人らしく、確かに大規模案件を成功させてきた実績のある人らしい。

本人も自分のことだと認めるような発言をしていた。
(ただしもちろんブログの内容自体を認めているわけではない)

私は彼のツイートも読み漁った。

ブログにはプロジェクトの参画者をツイッターで募ったもののそのツイートが非常識で時代錯誤なものであったため誰も集まらなかったと書いてあるのだが、その求人ツイートも確認できた。

その後プロジェクトが難航して参画者が「逃げた」ので仕切り直しになったということもツイートしており、ブログに書かれていることがおおまかに事実であることがわかった。

このプロジェクトはDBを使ったアプリケーションの開発のようで、私の仕事とは少し違う分野なのだが、私の仕事でも「PM」、「仕様と実装」みたいなものがあるのは同じである。

かなり古い時代だが、DBを使ったアプリケーション構築もしたことがある。

そして、批判されている「PM」は、私と同年代であり、
批判している人は若く、せいぜい30代くらいと思われる。

そのことが、私に彼への批判をそのまま受け取りにくくさせた。

面倒なので、ブログを書いた人をA君、批判された「PM」をB氏としよう。

さっきからずっと「PM」とカッコにくくっているが、それはA君はあまりにPM(プロジェクトマネージャー)の役割やあるべき姿に対して固定観念を持ちすぎであると感じたからだ。

A君が思い描いていたPMの姿、それはどこから得たものかわからない。本で読んだのか、過去に参画したPM達の仕事ぶりからの一般論なのか。

確かにプロジェクトマネジメントに関する資格はあり、その保持者でないとPMになれない、というプロジェクトもあるが、医師、弁護士、会計士、税理士といった資格とは違って、「よく勉強している人」程度のものでしかなく、PMの資格をもっていないとシステム開発をおこなえないわけではない。

この話で一番感じたのがこのA君の一方的なPM像についての違和感である。

そして次に、この話のタイトルにもなっている、大規模プロジェクトを少人数で担当したという点である。

A君はプロジェクトの規模が大きいことを金額で示した。

これにも違和感がある。

そもそも彼が書いている「数億円」という規模は、B氏が受注した金額ではなく、
他の有名企業が見積もった金額らしい。

そしてB氏はそれをはるかに下回る金額と短納期で受注したようなのだ。

私はあまり工数や費用の見積もりに詳しくないが、
ことITに関しては非常に難しく、開発する側の立場としてはほとんどの場合過剰に高額に見積もられていると感じる。

それは多分多くの人が自覚している。私も、『こんなことでこんなに貰えるならもっと安い金額で自分でやろうかな』と思ったことが何度もある。

おそらくB氏は私が思っただけで終わってしまったことを実行に移したのである。

どうやらB氏はPMだけでなく営業もしており、さらに企業の社長であり講演などもおこなっている。そしてもともと自分自身で手を動かし開発してきた技術者であり、いまでも自身で開発業務もおこなっているようである。

現在私の職場では、PMという役割は基本的に技術的なことにタッチしない。ほとんどのPMは技術者あがりで自分は手を動かさないものの技術的なことを理解はしている。

しかし中には、ほとんど技術的なことを理解しておらず、自分以外の誰かに仕事を割り当てて顧客の要求をそのまま横流しするようなPMやPLを見かける。
この話もそのようなことなのかなと思った。

私も、「仕様のないプロジェクト」というものに参画したことがある。
「仕様がなくてはできません」と文句を言ったこともある。

しかし後から振り返ってみれば、私が想定していたピラミッドのようにきれいに階層化されて、上から顧客の要求を注ぎ込むと、あとはコーディングするだけの技術仕様ができるような組織なんて、ユートピアのようなほとんどありえないものだったとわかる。

そのように見えるプロジェクトには必ずスーパーマンがいて、常人の何十倍何百倍の効率で仕事をしている人がいるのだ。その「何百倍」というのは労働時間のことではない。

IT業界で長年にわたり問題になっているのは工数を人数×労働時間「人日」で見積もることである。

どんな業界でも労働時間が生み出す価値に必ずしも比例するものではないが、IT業界、開発業務においてはとくにそれが著しいと思う。

極端な例を言うと、バグだらけのシステムを開発して長い時間をかけて改修し続ければ、納期に間に合わせさえすれば時間をかければかけるほど開発者は多くの報酬を得るのである。

ソフトウェア開発も「設計」、「構築」、「開発」などどという言葉を使うが、物理的な建築物にくらべて制約が極端にゆるく無制限といっていいくらい柔軟な対応ができる。

言語やツールも豊富にありどれを使っても自由だ。

だから、工数などというものも、やる前から見積もるのは非常に難しくほとんど意味がないとさえ言えるのだ。

やりようによっては10人で1か月かかるし、1人で一週間で終わる。

大人数でやると、開発そのものと同じかひどい場合はそれを上回る情報共有や進捗管理の工数が発生する。

私が経験してきたプロジェクトはほとんどが中身に比して人員過剰管理過剰になっていて、それによってかえって労働時間が増え品質も低下していると感じる場合がほとんどだった。

うまくいったプロジェクトは少人数で、ある程度気心のしれたメンバーでとくにルールもなく柔軟に対応していたものだった。

だが、その個人の裁量にまかせる柔軟なやり方は大規模で大人数のプロジェクトではうまくいかない。そういう「わかっている」人達は大規模組織で守るべきプロセスがかったるくて実力もでない。(私の実体験A)

一方、強力な管理体制をしいてプロセスやルールも厳密にしたプロジェクトはほとんど何も知らない人を使っても一応動くが、膨大な無駄な印刷物が発生したり、常識では考えられないミスが見過ごされることがある。(私の実体験B)

私の実体験AとBを比べると、Aの方がマシだった。Aではプロジェクト内に論争が絶えなかったが常に皆が何かを考え改善しようという動きがあった。

Bではニュースになるほどの大規模障害を発生させたことがありその反省から非常事態宣言が発令され、より一層堅固な管理体制がしかれていた。

具体的にはレビューの回数を増やす、作業実施時に確認者に加えてさらにそれを確認する確認者を付けるなど。

私が参画したのはその障害発生後だった。私はそのプロジェクトに参画して数か月くらいたって、障害の原因は管理体制の不十分さではなく、むしろ逆に管理しすぎたことではないかと思っていた。

そのプロジェクトでは私を含め、とにかく楽をしよう、失敗をさけよう、という気持ちが蔓延していて、より良いものを作ろうなどという意識は誰も持てなくなっていた。


暴露話の件に戻る。

もうひとつ、決定的な齟齬を生んでいたと思われるのは、B氏は機能単位で報酬を決めていたのに対し、A君は最初から最後まで時間単位で考えていたと思われるところである。

「(1か月)100時間しか参加できないと伝えていたのにフルタイムということになっていた」
というところにそれが見える。

B氏が受注したのはおそらく人日に基づいて見積もられた金額とスケジュールに対し、機能に基づいて見積もられた金額とスケジュールであったからだろう。
そういうことをツイートしていた。

B氏は必要な機能を完成させさえすれば1時間でも50万払うし、できるまではどれだけかかろうと完成させろということだったのだろう。

契約的にはどれだけかけても完成させるというのは無理だろうから、報酬を出さないとか
減額するとかいうことになるのだろうが、その辺がどうだったのかはわからない。

B氏のとにかく機能が実装できればやり方は問わないという姿勢をA君は理解できず自分が経験してきたあるいは知っている方法でやることにこだわりすぎ最後までかみ合わなかった。

私はB氏と同年代なのだが、仕事に対する考え方はA君に近い。

B氏のようなやり方の人とはあまり相性がよくない。

「指示されたことだけやるのではなく自主的に動け」というのは若いころからよく言われて、『そんなこといったって...』と不満に思いながらも確かに自分の自主性や積極性のなさは欠点だと感じ続けていた。

スティーブジョブズなんかもかなりの曲者だったらしい。

皆がA君が考えているような仕事のしかたをするようになれば楽に働けるようにはなるかもしれない。

でもきっと、そういう職場からはおもしろいモノは生まれないだろうし、働いていても死ぬほど退屈だろうな.... とも思う。

2020/01/31

ConoHaのVPS

さくらのVPSを1台借りていて2つのドメインで使用しているのだが、

やっぱり物理的に(VPSだから本当は物理的にではないが)2台ほしくなってきた。

さくらのVPSには何の不満もないのだが、VPSってほかにもないのかなと調べてみたら、
なんとConoHaというサービスの利用者はさくらより多いということを知った。

てっきりVPSといえばさくらだと思っていたのだが。

サービス内容をざっと見したところさくらとそんなに違うところはない。

初期費用がない、特定の用途向けのパッケージみたいなものがある、
というのが気づいたところ。

OSはCentOS8にした。去年リリースされたそうだ。

ようやくCentOS7に慣れたところだが、きっとこれから使うことになると思うので
勉強を兼ねて。

6→7 ほどの違いはないっぽい。

yumがdnfというものになっているそうだが、yumも使える。

yumはpython2ベース、dnfはpython3ベース。

python2と3のゴタゴタは嫌だったのでこっちの方がいい。



2020/01/18

TCPまたはUDPパケットを送信する。javaで。

UDPかTCPを指定できるようにした。 Clientx.java
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.io.DataOutputStream;
import java.net.Socket;


public class Clientx {
 public static void main(String[] args) throws IOException{
  String sendData = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";

  String Host = args[0];
  Integer DstPort = Integer.parseInt(args[1]);
  int count = Integer.parseInt(args[2]);
  String Proto = args[3];
 
  System.out.println(Proto);

  if (Proto.equals("U")) {
   UDPsend(sendData,Host,DstPort,count);
  }else{
   TCPsend(sendData,Host,DstPort,count);
  }
 }

 public static void UDPsend(String sdata, String host, int dstPort, int count) throws IOException{
  byte[] bdata = sdata.getBytes("UTF-8");
  DatagramSocket sock = new DatagramSocket();
  DatagramPacket packet 
  = new DatagramPacket(bdata, bdata.length, new InetSocketAddress(host,dstPort));


  for(int i=1; i<=count; i++) {  
   sock.send(packet);
   System.out.println("Sent UDP data  "+host+":"+dstPort);
    try{
    Thread.sleep(1000);
   }catch(InterruptedException e){}
  }
  sock.close();//
 }

 public static void TCPsend(String sdata, String host, int dstPort, int count) {
  try{

   for(int i=1; i<=count; i++) {  
    Socket sock = new Socket(host,dstPort);
    DataOutputStream out = new DataOutputStream(sock.getOutputStream());
    out.writeUTF(sdata);
    System.out.println("Sent TCP data  "+host+":"+dstPort);

    out.close();
    sock.close();
     try{
     Thread.sleep(1000);
    }catch(InterruptedException e){}
   }

  }catch(IOException e){
   e.printStackTrace();
  }

 }
}
------------- 

 使い方 

 TCP12345のパケットを5個送信 

java Clientx localhost 12345 5 T 

 UDP12345のパケットを5個送信 

java Clientx localhost 12345 5 U 

 実際は4番目の引数が"U"ならUDP、それ以外だとTCPになる。 

4番目の引数がないと動かない。 

UDPの場合はport unreachableが返ってきてもとりあえず送信はするが、 
TCPの場合受信者がいないと(指定したTCPポートをリッスンしていない)と、 
1回送ってExceptionを吐いて終了してしまう。 

 TCPのサーバも作った。 TCPのサーバ 

 ServerT.java
import java.io.IOException;
import java.io.DataInputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerT {
 public static void main(String[] args) {
  try{
   while(true){
    ServerSocket svSock = new ServerSocket(12345);
    Socket sock = svSock.accept();
    DataInputStream in = new DataInputStream(sock.getInputStream());
    String strData = in.readUTF();
    System.out.println("Received TCP : "+strData);
    in.close();
    svSock.close();
   }
  }catch(IOException e){
   e.printStackTrace();
  }

 }
}
UDP/TCPどっちでも受信できるようにするのはまた今度。

任意のパケットを送信する。javaで。UDP編

たとえばFirewallのポリシーの設定確認のときに、任意のパケットを送信したいことがある。 UDP 1234とか、TCP 5678とか。

ICMPならpingを打てばよいし、HTTP、HTTPS、SSH、TELNETなどならブラウザやteratermで実際にアクセスしてみればいい。TCPならtelnetでポート指定すればよいが、UDPの特定のポートの通信を発生させるためにはツールを使っていた。ipsendwinとか、iperfとか。 ixiaのトラフィックジェネレータを使ったこともある。

最近もipsendwinを使ったのだが、もう古いソフトで、Vectorのダウンロード画面ではサポートOSに「Windows XP/Me/2000/NT/98/95」と書いてある。 そしてあるPCでは「winpcap.dllがない」と表示され、コピーするもまた違うdllがない、エントリポイントが見つからない、などどいうことで実行するのをあきらめた。

そして、このご時世、いろんなアプリやスクリプトがあるし、「UDP 1234のパケットを特定のIPアドレスに10個ほど送信する」なんてことは簡単にできるんじゃないのかと思った。

pythonとかjavascriptとかさらっと調べたが、結局javaでやった。

java。 ちょっと、今更java?みたいな感じがした。 javaで簡単なプログラムを書いたことはあり、 簡単に書けて「ネットワークプログラミングならjavaだな」と思った。

しかし、javaは当然インストールされているだろうと思って普段仕事でつかっているPCのコントロールパネルを見たがjavaがインストールされていない。 たしかコントロールパネルにjavaのアイコンがあったはず.... もう最近はjavaが使われなくなりつつあるのか?

というわけでjavaのインストールから始める。 「java ダウンロード」などで検索するとダウンロードページがすぐ出てくるが、 32ビット版をインストールするように導かれる。 今なら、Version 8 Update 241 64ビット版もあるようだがどういうことだろうと少し調べたら、 ブラウザが32ビット版がデフォルトなのでjavaも32ビット版を使え、ということだった。

https://java.com/ja/download/faq/java_win64bit.xml

普段はクロームを使っているが64ビット版である。 が、たしかクロームでjavaが使えなくなったんじゃなかったっけ...?

IEはたしかに32ビット版のようである。使っていないが。 javaのランタイムは32ビット版のインストールページが検索すると上位に表示されるが、 開発環境、jdkだと13.0.2の64ビット版が出てくる。

32ビット版のランタイムがインストールされているところに64ビット版のjdkをインストールすると、実行時にエラーになる。 ランタイムは入れず、入っていたらアンインストールし、64ビット版のjdkをインストールする。 インストールしたら、binフォルダへのpathを登録する。

C:\Program Files\Java\jdk-13.0.2\bin

pathを登録したらコマンドプロンプトを開いてバージョンを確認してみる。

C:\WINDOWS\system32>javac -version
javac 13.0.2

HelloWorld.java を作る。

public class HelloWorld{
   public static void main(String[] args){
     System.out.println("Hello World!!");
   }
}
javac HelloWorld.java

でコンパイル。 HelloWorld.class ができる。

 実行。

C:\WINDOWS\system32>java HelloWorld
Hello World!!

では、UDPの任意のパケットを送信するプログラムを書こう。

 Client.java

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
public class Client {
 public static void main(String[] args) throws IOException {
  String sendData = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
  byte[] data = sendData.getBytes("UTF-8");
  DatagramSocket sock = new DatagramSocket();
   int count = Integer.parseInt(args[2]);
  String Host = args[0];
  Integer DestPort = Integer.parseInt(args[1]);
   for(int i=1; i<=count; i++) {  
   DatagramPacket packet 
   = new DatagramPacket(data, data.length, new InetSocketAddress(Host,DestPort));
   sock.send(packet);
   System.out.println("Sent UDP data  "+Host+":"+DestPort);
    try{
    Thread.sleep(1000);
   }catch(InterruptedException e){}
   }  
   sock.close();//
 }
}

使い方
java Client 宛先 ポート番号 パケット数

たとえば

java Client 192.168.1.1 12345 5

192.168.1.1宛に、UDP の宛先ポート12345のパケットを5個送信する。
間隔は1秒

送るだけならこれで終わり。 もし指定したIPアドレスのホストが存在しないと、arp解決されずパケットが送信されないだろう。 指定したIPアドレスのホストが存在すればパケットが送信されるが、 テキトーなポート宛に送っているので、port unreachableが返ってくるだろう。 送ったパケットを受信しそれを確認したい場合は受信側で下記を実行する。

Server.java

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.Arrays;
public class Server {
        public static void main(String[] args) throws IOException {
                Integer Port = Integer.parseInt(args[0]);
                while (true) {
                        DatagramSocket sock = new DatagramSocket(Port);
                        byte[] data = new byte[1024];
                        DatagramPacket packet = new DatagramPacket(data, data.length);
                        sock.receive(packet);
                        System.out.println("Received :"+new String(Arrays.copyOf(packet.getData(),packet.getLength()),"UTF-8"));
                        sock.close();
                }
        }
}

動作確認 Client.javaとServer.javaをコンパイルしたら、 コマンドプロンプトを二つ起動して、 Client.classとServer.classがあるフォルダに移動し、片側でサーバを起動するこのときポート番号を指定する。

C:\Users\sam\udp_data_send>java Server 12345

もう一方でクライアントを起動する。
C:\Users\sam\udp_data_send>java Client localhost 12345 10
Sent UDP data  localhost:12345
Sent UDP data  localhost:12345
Sent UDP data  localhost:12345
Sent UDP data  localhost:12345
Sent UDP data  localhost:12345
Sent UDP data  localhost:12345
Sent UDP data  localhost:12345
Sent UDP data  localhost:12345
Sent UDP data  localhost:12345
Sent UDP data  localhost:12345
C:\Users\sam\udp_data_send>java Server 12345
Received :0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
Received :0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
Received :0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
Received :0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
Received :0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
Received :0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
Received :0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
Received :0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
Received :0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
Received :0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
TCPはまた今度。