|
|
By utahta, on 1月 24th, 2010%
pthread_key 周辺の使い方を勉強。
スレッドごとにメモリ領域を確保する仕組み。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
static pthread_key_t g_key;
// スレッド単位で保持するデータ
struct MyData{
int count;
char data;
};
static void* thread_call( void *arg )
{
pthread_t self_id = pthread_self();
printf( "self_id:%u\n", self_id );
// データがすでに存在するか調査
struct MyData *p;
if( pthread_getspecific( g_key ) ){
printf( "self_id:%u Already exists.", self_id );
return NULL;
}
// データ作成
if( !(p = (struct MyData *)calloc( 1, sizeof(*p) )) ){
perror( "calloc()" );
return NULL;
}
pthread_setspecific( g_key, p );
p->count = 0;
p->data = 'A';
// 本当にスレッド単位で保持されているかテスト
int i;
for( i = 0; i < 26; ++i ){
p = (struct MyData *)(pthread_getspecific( g_key ));
printf( "self_id:%u id:%u data:%c\n", self_id, p->count++, p->data++ );
usleep(1000);
}
p = (struct MyData *)(pthread_getspecific( g_key ));
if( p->count == 26 ){
printf( "self_id:%u success.\n", self_id );
}
else{
printf( "self_id:%u error!!\n", self_id );
}
// 終了
free(p);
pthread_setspecific( g_key, 0 );
}
int main()
{
// pthread key を初期化
if( pthread_key_create( &g_key, NULL ) ){
perror( "pthread_key_create()" );
return 0;
}
// スレッドを複数作成。
const int TNUM = 3;
pthread_t tid[TNUM];
int i;
for( i = 0; i < TNUM; ++i ){
if( pthread_create( &tid[i], NULL, thread_call, NULL ) ){
perror( "pthread_create()" );
continue;
}
printf( "Created a thread. id:%u\n", tid[i] );
}
// 全スレッドが終了するのを待機。
for( i = 0; i < TNUM; ++i ){
pthread_join( tid[i], NULL );
}
// pthread key を削除
pthread_key_delete( g_key );
return 0;
}
実行
$ gcc main.c -lpthread
$ ./a.out
Created a thread. id:663552
Created a thread. id:2625536
Created a thread. id:3162112
self_id:663552
self_id:2625536
self_id:3162112
self_id:663552 id:0 data:A
self_id:2625536 id:0 data:A
self_id:3162112 id:0 data:A
self_id:663552 id:1 data:B
self_id:2625536 id:1 data:B
...
self_id:2625536 id:25 data:Z
self_id:663552 success.
self_id:3162112 id:25 data:Z
self_id:2625536 success.
self_id:3162112 success.
By utahta, on 1月 14th, 2010%
send と recv の正しい使い方と送信バッファ溢れについて。
manpage
Manpage of SEND
Manpage of RECV
SEND
non-blocking の場合。
send が失敗して外部変数 errno に EINTR が設定されている場合は、再度送信を試みる必要がある。
データをソケットの送信バッファに入れることが出来ない場合、外部変数 errno に EAGAIN か EWOULDBLOCK が設定される。
いつデータが送信できるようになるかを知るために select などのシステムコールを使うことが出来る。(後述:送信バッファ溢れ)
以下、ソースコードから抜粋した send のサンプル。
int res = 0;
char* p = buffer; // 送るデータ
size_t len = buffer_size; // 送るデータのサイズ
while( len > 0 ){
while( true ){
res = send( socket, p, len, MSG_DONTWAIT ); // 一度に全部送れるとは限らない
if( errno != EINTR ) break; // システム割り込みチェック
}
if( res < 0 ){
if( errno == EAGAIN ||
errno == EWOULDBLOCK ){
// 書き込めない状態。それなりの対応が必要(後述:送信バッファ溢れ)
}
else{
// なんらかのエラー(コネクション切断とか)
}
}
len -= res;
p += res;
}
RECV
non-blocking の場合。
操作が停止するような場合、外部変数 errno に EAGAIN か EWOULDBLOCK が設定される。
以下、ソースコードから抜粋した recv のサンプル。
int res = 0;
while( true ){
res = recv( socket, buffer, buffer_size, MSG_DONTWAIT );
if( errno != EINTR ) break;
}
if( res == 0 ){
// EOF
}
if( res < 0 ){
if( errno == EAGAIN ||
errno == EWOULDBLOCK ){
// not ready yet.
}
else{
// error.
}
}
送信バッファ溢れ
データ送信時に送信バッファが溢れてしまった場合、書き込み可能なタイミングを見計らって、溢れたデータを再送信してあげる必要がある。
送信バッファが溢れたとき、send 関数は失敗し、errno に EAGAIN, EWOULDBLOCK を格納する。
対策として例えば、送信データをキューなり可変長バッファなりで一時的に保持し、select などで書き込み可能になるタイミングを監視して、再送信する方法がある。
サンプル:sendbuffer-test
事前に libevent をインストールしておく必要あり。
動作環境 Linux のみ。(送信バッファと受信バッファの数値を linux/sockios.h 使って確認してる為)
1.サーバは受信時に3秒間待機する。
2.クライアントはサーバへデータを送信しまくり、EAGAIN or EWOULDBLOCK を発生させる。
3.エラー発生後、クライアントは書き込み可能イベントを監視し、検知したらデータを再送信する。
2ー3の動作を繰り返し、サーバに規定のデータ(0 – 499 までの連番)が全部届いたら成功。
インストール
$ git clone http://github.com/utahta/sendbuffer-test.git
$ cd sendbuffer-test
$ ./configure --prefix=/path/to/sendbuffer-test --with-libevent=/path/to/libevent
$ make
$ make install
実行
コマンドプロンプトをふたつ立ち上げ、1つめにサーバを起動します。
$ /path/to/sendbuffer-test/bin/sbt_server
2つめにクライアントを起動します。
$ /path/to/sendbuffer-test/bin/sbt_client
手元では、以下のような結果になりました。
$ /path/to/sendbuffer-test/bin/sbt_server
connected. sd:7
recv buffer size:274 sd:7
waiting 3 sec.
... 省略
message received. sd:7 str:abcdefghijklnmopqrstuvwxyz:495
message received. sd:7 str:abcdefghijklnmopqrstuvwxyz:496
message received. sd:7 str:abcdefghijklnmopqrstuvwxyz:497
message received. sd:7 str:abcdefghijklnmopqrstuvwxyz:498
message received. sd:7 str:abcdefghijklnmopqrstuvwxyz:499 // 499 まで届いた
$ /path/to/sendbuffer-test/bin/sbt_client
send buffer size. :50436
... 省略
send buffer size:48498 res:0 sd:6
send buffer size:48772 res:0 sd:6
send buffer size:49046 res:0 sd:6
not ready yet: Resource temporarily unavailable // 書き込み失敗
send buffer size:49152 res:-10 sd:6
not ready yet: Resource temporarily unavailable
send buffer size:49152 res:-10 sd:6
... 省略
resend buffer size:88558 res:0 sd:6 // 書き込み可能になったので再送信
このサンプルでは、可変長処理をさぼってあらかじめ大きなバッファを確保してごまかしてたり。
終了処理に手抜きがあったり。(delete してなかったり)
とりあえずサンプルということで。
By utahta, on 1月 10th, 2010%
下書きで放置していたSNMPに関するメモ。
インストール
Net-SNMPからソースをダウンロード。
$ tar zxvf net-snmp-5.4.2.1.tar.gz
$ cd net-snmp-5.4.2.1
$ ./configure --prefix=/usr/local/net-snmp-5.4.2.1 --disable-embedded-perl --without-perl-modules
************** Configuration Section **************
-Press return to continue-
Default version of SNMP to use (3):
System Contact Information (@):
System Location (Unknown):
Location to write logfile (/var/log/snmpd.log):
Location to write persistent information (/var/net-snmp):
$ make
# make install
必要であれば、エイリアスを設定。
$ cd /usr/local
# ln -s net-snmp-5.4.2.1 net-snmp
SNMP設定
# vi /usr/local/net-snmp/snmpd.conf
... 以下、設定内容。
com2sec hogetest 192.168.11.0/24 hogetest_com
com2sec hogetest localhost hogetest_com
group hogetest_grp v1 hogetest
view hogetest_view included .1.3.6.1.4.1.2021
access hogetest_grp "" any noauth exact hogetest_view none none
exec writetest /usr/local/net-snmp/a.sh
...
アクセスサンプル用のテキスト
# vi /usr/local/net-snmp/a.sh
/bin/echo aaa
起動
# snmpd -Lsd -Lf /var/log/snmpd.log -p /var/run/snmpd -a
-Lsd : syslogを有効にする
-Lf : snmpdの出力を送るファイル名の指定
-p : ファイル名 プロセスIDを保存するファイル名
-a : 送信元IPアドレス(NMS)をログに記録する
OIDを取得
英文字の形(OID = name)
$ ./snmpwalk -OQS -c hogetest_com -v 1 localhost .1.3.6.1.4.1.2021.8.1.extNames | grep writetest
数値の形(OID = name)
$ ./snmpwalk -OQSn -c hogetest_com -v 1 localhost .1.3.6.1.4.1.2021.8.1.extNames | grep writetest
値(exec)を取得
$ ./snmpget -c hogetest_com -v 1 localhost UCD-SNMP-MIB::extOutput.1
UCD-SNMP-MIB::extOutput.1 = STRING: aaa
$ ./snmpget -OQv -c hogetest_com -v 1 localhost UCD-SNMP-MIB::extOutput.1
aaa
参考
NET-SNMPのインストール
SNMPによるネットワークシステムの監視
SNMPによるネットワークモニタリング
By utahta, on 1月 10th, 2010%
下書きで放置していた cacti に関するメモ。
インストール
$ tar zxvf cacti-0.8.7a.tar.gz
$ cp cacti-0.8.7a /path/to/
$ cd /path/to
$ ln -s cacti-0.8.7a cacti
$ cd cacti/include
$ vi config.php
apache のエイリアスをきってからアクセス。
アクセス先は、http://path/to/cacti/ とか。
0.8.7b バグ
Invalid PHP_SELF Path とか表示されたら、下記のように修正すればよいらしい。
(- が修正前、+ が修正後。-, + は実際はいらない)
include/global.php 113行目
- if (!((is_file($_SERVER["SCRIPT_FILENAME"])) && (substr_count($_SERVER["SCRIPT_FILENAME"], $_SERVER["PHP_SELF"])))) {
+ if (!((is_file($_SERVER["SCRIPT_FILENAME"])))) {
新しい定義
- スクリプトを書く
- DataInputMethod を cacti で定義。
- Data Templates を cacti で定義。
- Data Sources を cacti で定義。
- Graph Templates を cacti で定義。
By utahta, on 1月 8th, 2010%
TCPサーバのサンプルコードのメモ。
簡単なコードだからか、何度も書いてはどこかへやってたのでいい加減保存することに。
動作は一応 Linux CentOS5, Mac OS X 10.6 で確認済み。
server/main.cpp に socket, bind, listen, accept, select, recv など。
client/main.cpp に socket, connect, send など。
ソースコード
easy-tcpserver
インストール
$ git clone http://github.com/utahta/easy-tcpserver.git
$ cd easy-tcpserver
$ ./configure --prefix=/path/to/easy-tcpserver
$ make
$ make install
実行
・サーバ
$ cd /path/to/easy-tcpserver/bin
$ ./easy_tcpserver
・クライアント
$ cd /path/to/easy-tcpserver/bin
$ ./easy_tcpclient
By utahta, on 11月 17th, 2009%
libevent のソースコードを参考にしつつ epoll を使ってみたメモ。
ただの興味本位。
動作は、Linux CentOS 5 で確認。
エラー処理とかはやってたりやってなかったり、わりと適当。
server.cpp
/**
* @file server.cpp
* @brief epoll test server.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/epoll.h>
#define LISTEN_PORT (12345) ///< 待ち受けポート
#define MAX_EVENTS (1000) ///< 最大イベント数
#define MAX_BACKLOG (10) ///< リクエスト待機キューの格納数
struct epollev
{
void (*callback)(int, void *); ///< callback function.
void *arg; ///< user data.
};
struct epollop
{
int epfd; ///< epoll fd.
struct epoll_event *events; ///< epoll events.
int num_events; ///< maximum number of events.
struct epollev *fds; ///< fds
};
static epollop g_epollop;
static void callback_accept( int fd, void *arg );
static void callback_client( int fd, void *arg );
//! @brief 強制終了
static void server_exit( const char *log )
{
perror( log );
exit( EXIT_FAILURE );
}
//! @brief イベント初期化
static void server_init()
{
int epfd, nfiles = MAX_EVENTS;
if( ( epfd = epoll_create( nfiles ) ) == -1 ){
server_exit( "epoll_create()" );
}
g_epollop.epfd = epfd;
g_epollop.events = new struct epoll_event[nfiles];
memset( g_epollop.events, 0, sizeof(struct epoll_event)*nfiles );
g_epollop.num_events = MAX_EVENTS;
g_epollop.fds = new epollev[nfiles];
memset( g_epollop.fds, 0, sizeof(struct epollev)*nfiles );
}
//! @brief イベント追加
static void server_add( int fd, int events, void (*callback)(int, void *), void *arg )
{
struct epoll_event epev = {0, {0}};
struct epollev *ev = &g_epollop.fds[fd];
int op = EPOLL_CTL_ADD;
if( ev->callback != NULL ){
op = EPOLL_CTL_MOD;
}
epev.data.fd = fd;
epev.events = events;
if( epoll_ctl( g_epollop.epfd, op, fd, &epev ) == -1 ){
perror( "epoll_ctl()" );
return;
}
ev->callback = callback;
ev->arg = arg;
}
//! @brief イベント削除
static void server_del( int fd )
{
struct epoll_event epev = {0, {0}};
struct epollev *ev = &g_epollop.fds[fd];
int op;
op = EPOLL_CTL_DEL;
epev.data.fd = fd;
memset( ev, 0, sizeof( struct epollev ) );
if( epoll_ctl( g_epollop.epfd, op, fd, &epev ) == -1 ){
perror( "epoll_ctl()" );
return;
}
close( fd );
}
//! @brief 受付
static void server_listen()
{
int sock;
struct sockaddr_in saddr;
if( ( sock = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ){
server_exit( "socket()" );
}
memset( &saddr, 0, sizeof( saddr ) );
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl( INADDR_ANY );
saddr.sin_port = htons( LISTEN_PORT );
if( bind( sock, (struct sockaddr *) &saddr, sizeof(saddr) ) != 0 ){
close( sock );
server_exit( "bind()" );
}
if( listen( sock, MAX_BACKLOG ) < 0 ){
close( sock );
server_exit( "listen()" );
}
server_add( sock, EPOLLIN, callback_accept, NULL );
}
//! @brief メインループ
static int server_loop( )
{
fprintf( stdout, "in server_loop.\n" );
while( true ){
int i, res;
int timeout = -1;
struct epoll_event *events = g_epollop.events;
res = epoll_wait( g_epollop.epfd, events, g_epollop.num_events, timeout );
if( res == -1 ){
server_exit( "epoll_wait()" );
}
for( i = 0; i < res; ++i ){
int fd = events[i].data.fd;
struct epollev *ev = &g_epollop.fds[fd];
ev->callback( fd, ev->arg );
}
}
return 0;
}
//! @brief 受付コールバック
static void callback_accept( int fd, void *arg )
{
fprintf( stdout, "in callback_accept. fd:%d\n", fd );
int sock;
struct sockaddr saddr;
socklen_t len = sizeof( struct sockaddr_in );
if( ( sock = accept( fd, (struct sockaddr *)&saddr, &len ) ) < 0 ){
perror( "accept()" );
return;
}
int flag = fcntl( sock, F_GETFL, 0 );
fcntl( sock, F_SETFL, flag | O_NONBLOCK );
fprintf( stdout, "accept. sock:%d\n", sock );
server_add( sock, EPOLLIN, callback_client, NULL );
}
//! @brief クライアントコールバック
static void callback_client( int fd, void *arg )
{
fprintf( stdout, "in callback_client. fd:%d\n", fd );
char buff[1024];
int ret = ::recv( fd, buff, sizeof(buff), 0 );
if( ret <= 0 ){
fprintf( stdout, "exit. fd:%d ret:%d\n", fd, ret );
server_del( fd );
}
else{
fprintf( stdout, "fd:%d -> %s\n", fd, buff );
}
}
int main()
{
server_init();
server_listen();
return server_loop();
}
client.cpp
/**
* @file client.cpp
* @brief test client.
*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#define CONNECT_ADDR "127.0.0.1"
#define CONNECT_PORT (12345)
bool setnonblock(int fd)
{
int flags = fcntl( fd, F_GETFL );
if( flags < 0 ){
return false;
}
if( fcntl( fd, F_SETFL, flags |= O_NONBLOCK ) < 0 ){
return false;
}
return true;
}
int main(void)
{
int ret = 0, sock = 0, clilen = 0;
struct sockaddr_in cliaddr;
// socket
if( ( sock = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ){
puts( "socket error!!" );
return 1;
}
memset( &cliaddr, 0, sizeof( cliaddr ) );
cliaddr.sin_addr.s_addr = inet_addr( CONNECT_ADDR );
cliaddr.sin_family = AF_INET;
cliaddr.sin_port = htons( CONNECT_PORT );
clilen = sizeof( cliaddr );
if( ( ret = connect( sock, (struct sockaddr *)&cliaddr, clilen ) ) < 0 ){
perror( "connect()" );
return 1;
}
if( !setnonblock( sock ) ){
perror( "setnonblock()" );
}
puts( "in client loop." );
char str[1024];
char *strpos;
while( 1 )
{
memset( str, 0, sizeof( str ) );
fgets( str, sizeof(str), stdin );
// \n を除去
if( ( strpos = strchr( str, '\n' ) ) != NULL ){
(*strpos) = '\0';
}
// exit
if( strncmp( str, "exit", 4 ) == 0 )
break;
// send
if( send( sock, str, strlen( str ) + 1, 0 ) < 0 ){
perror( "send()" );
break;
}
}
// 後始末
while( 1 ){
ret = recv( sock, str, sizeof(str), 0 );
if( ret <= 0 )
break;
}
close( sock );
return 0;
}
By utahta, on 10月 27th, 2009%
core ファイルを解析するメモ。
下準備
まず意図的に SEGV させるコードを書く。
#include <stdio.h>
class CPrint
{
private:
int m_number;
char *m_str;
public:
CPrint() : m_number(10), m_str(NULL) {}
~CPrint() {}
void print(){
// ここで SEGV る予定
printf( "%d, %c\n", m_number, m_str[0] );
}
};
int main()
{
CPrint p;
p.print();
return 0;
}
続けて core を出力させる設定。環境は Linux CentOS 5。
core dumped
下準備で作成したソースコードをコンパイル。-g を忘れずに。
実行する。当然 SEGV る。
$ ./a.out
セグメンテーション違反です (core dumped)
core ファイルが吐かれていることを確認。
$ ls
a.cpp a.out core.1613
core 解析
gdb を立ち上げる。gdb 実行バイナリ coreファイル
$ gdb a.out core.1613
...
Program terminated with signal 11, Segmentation fault.
#0 0x08048568 in CPrint::print (this=0xbfe45794) at a.cpp:15
15 printf( "%d, %c\n", m_number, m_str[0] );
(gdb)
呼び出された順番で関数を表示する。
(gdb) where
#0 0x08048568 in CPrint::print (this=0xbfe45794) at a.cpp:15
#1 0x080484fd in main () at a.cpp:22
(gdb)
ソースコードを表示する。
(gdb) list
10 CPrint() : m_number(10), m_str(NULL) {}
11 ~CPrint() {}
12
13 void print(){
14 // ここで SEGV る予定
15 printf( "%d, %c\n", m_number, m_str[0] );
16 }
17 };
18
19 int main()
(gdb)
変数の値を確認する。
クラスのメンバ変数もアドレスさえ分かれば確認できる。
(gdb) p ((class CPrint *) 0xbfe45794)->m_number
$2 = 10
(gdb)
いちいち ((class CPrint *) 0xbfe45794) とうつのが面倒な場合は、変数に代入する。
(gdb) set $c = ((class CPrint *) 0xbfe45794)
(gdb) p $c->m_number
$3 = 10
(gdb) p $c->m_str
$4 = 0x0
By utahta, on 10月 27th, 2009%
自宅サーバのネットワークが突如不安定になる問題の解決メモ。
samba 経由で 10GB 程度のファイルをダウンロードしていると、サーバと通信が途切れてその後まともに通信出来なくなるという現象。
上記なことをしなければまったく問題なかったので、解決まで時間がかかったかかった。
いろいろ無駄な作業もしたけど、忘れがたい経験になったのでまとめメモ。
* 自宅サーバは CentOS 5.4 を使用しています。
* ディストリビューションによっては、そのまま従って解決というわけにいかないかもしれません。
原因追及
とりあえず情報収集。
手始めに /var/log/message を眺める。
いろいろあやしげな文字列がある中、ひときわ目立ってたのが次の1文。
$ vi /var/log/message
...
NETDEV WATCHDOG: eth0: transmit timed out
...
このメッセージが出た直後から、まともに ssh すらできない状態に陥るもよう。
最初はクライアント側の Mac のせいかと思って、Windows から同じことを試したりしたけど、状況は変わらず
いま思ってみれば、サーバにエラー的なメッセージが出ている時点でほぼ原因はサーバと断定して良かったかもしれない。
とにかく原因はサーバ側にあるらしいとこまで絞り込めた。
けど、具体的な症状はこの時点で当然ながらさっぱりだったので、引き続き情報収集。
# ifconfig
eth0 Link encap:Ethernet HWaddr 00:1C:C0:B4:F6:4A
inet addr:192.168.11.30 Bcast:192.168.11.255 Mask:255.255.255.0
...
# ethtool eth0
Settings for eth0:
...
Advertised auto-negotiation: Yes
Speed: 1000Mb/s
Duplex: Full
...
# lspci -v
...
01:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168B PCI Express Gigabit Ethernet controller (rev 02)
Subsystem: Intel Corporation Unknown device 0001
...
いろいろコマンドの使い方は分かったものの、原因はさっぱり。
調べた情報を元に google 先生と協力しながら、
ethtool で speed を 1000 から 100 にしてみたり。
# ethtool -s eth0 speed 100
TCP Segmentation Offload をオフにしてみたり。(後でもともとオフだったことに気づいたり)
# ethtool -K eth0 tso off
けれど、解決には至らず。
検索語を変えながらさらに調べていくと、
「NIC のドライバのバージョンが違うとネットワークが不安定になるよ」という情報を発見。
どうも NIC とドライバのバージョン関係に原因がありそうということが分かった。
解決編
先人の知恵をもとに NIC のバージョンとドライバを確認。
# lspci | grep Ether
01:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168B PCI Express Gigabit Ethernet controller (rev 02)
# lsmod | grep r81
... r8169 ですよ的な表示 ...
バージョンは、RTL8111/8168B。
インストールされているドライバは、r8169。
!!
RTL8111/8168B には、r8168 がインストールされていないとだめとのこと。
ここまで来れば解決したも同然!
さっそくドライバを再インストール。
ssh 経由 だとサーバから切断されて作業が中断されること請け合いなので、直接キーボードを繋いでの作業がオススメ。
事前に ドライバ をダウンロードしてサーバに置いておく。
作業時は r8168-8.014.00.tar.bz2 を /usr/local/src に置いた。
$ su -
# cd /usr/local/src
# rmmod r8169
# vi /etc/modprobe.conf
r8169 を r8168 に置換
...
# tar jxvf r8168-8.014.00.tar.bz2
# cd r8168-8.014.00
# vi readme
... すべき作業が書いてある...
# make clean modules
# make install
# man depmod
# depmod -a
# modprobe r8168
# lsmod | grep r8168
# reboot
以上のコマンドを叩いた結果、無事に samba 経由で 10GB 程度のファイルをダウンロードすることが出来るようになった。
まさかのドライバ違いに思わぬ時間を取られてしまったけど、いい経験になったかも。
参考
CentOSにNICを手動インストールした人は、正しいドライバが入っているかチェックしたほうがよさげ
By utahta, on 6月 15th, 2009%
setrlimit(2), getrlimit(2) メモ。
コマンドラインから ulimit -n 1024 などとせず、プログラム上から設定するやつ。
limits.conf 以上の値を割り当てようとすると失敗するぽい。
サンプルソース
#include <stdio.h>
#include <sys/time.h>
#include <sys/resource.h>
#ifndef RLIM_INFINITY
#define RLIM_INFINITY ((unsigned int)0xffffffff)
#endif
int main()
{
struct rlimit rl;
rl.rlim_cur = 0; /* ソフトリミット */
rl.rlim_max = 0; /* ハードリミット */
/* 現在設定されている値を取得する */
if( getrlimit( RLIMIT_NOFILE, &rl ) ){
puts( "getrlimit error." );
return 0;
}
printf( "before open_files:%d\n", rl.rlim_cur );
/* 制限なし状態かチェック */
if( rl.rlim_cur == RLIM_INFINITY ){
printf( "infinity:%d\n", rl.rlim_cur );
}
/* 試しに新しい値をセットしてみる */
rl.rlim_cur = 512;
/*rl.rlim_cur = 2048;*/
if( setrlimit( RLIMIT_NOFILE, &rl ) ){
puts( "setrlimit error." );
return 0;
}
/* さっき設定した値を取得する */
rl.rlim_cur = 0;
getrlimit( RLIMIT_NOFILE, &rl );
printf( "after open_files:%d\n", rl.rlim_cur );
return 0;
}
他にもスタックだったりcoreファイルサイズだったり色々変更できる。
詳しくは Manpage of GETRLIMIT で。
あんまし使わないけど知ってると便利っすなー。
By utahta, on 6月 5th, 2009%
最小構成の vim-minimal しか入っていなかったので追加インストールしたメモ。
# rpm -qa | grep vim
vim-minimal-7.0.109-4.el5_2.4z
# yum search vim
...
vim-X11.i386 : VIM バージョンの X Window System 用 vi エディタ
vim-common.i386 : すべてのバージョンの VIM エディタで必要とされる共通ファイル
vim-enhanced.i386 : 最新の拡張機能を持つバージョンの VIM エディタ
vim-minimal.i386 : 最小バージョンの VIM エディタ
# yum -y install vim-common vim-enhanced
...
Installed
# vi ~/.bashrc
alias vi='vim'
# source ~/.bashrc
|
|