set bit in specific position

find the bit of that position
int mask = 1 << pos;
value = src & mask;

clear the position of dst then set the bit to value
(dst & ~mask) | (value & mask);

#include 
#include 

int copy_bit(int src, int dst, int pos)
{
    int result = 0;
    int mask = 1 << pos;
    int value = 0;
    value = src & mask;
    return (dst & ~mask) | (value & mask);
}

#ifndef RunTests
int main()
{
    printf("%d", copy_bit(8, 12, 3));
}
#endif

I2C communication

most of the case when we communicate with a I2C driver
we prepare a unsigned char buffer to read/write to the I2C file node, since we cannot know the data read/write is positive or negative, so unsigned is the only way to store the value
and also we cannot know the order of the data(little endian or big endian), so char prevent us from doing miss-order

...
typedef struct {
        unsigned char func;
        unsigned char buffer[8];
} S_SensoryLicense;
...
uint32_t *securityChipComms(uint32_t * challenge)
{
        size_t ret = 0;
        int fd = 0;
        S_SensoryLicense SensoryLicense;
        static uint32_t respond[2];

        if (NULL == challenge) {
                printf("challenge is NULL\n");
                return (void *)-1;
        }

        /*
         * do the hardware communication with security IC
         * send challenge to IC
         * get respond from IC and place in 'respond'
         */
        fd = open(I2C_DEVICE_NAME, O_RDWR);
        if (fd < 0) {
                printf("open %s failed\n", I2C_DEVICE_NAME);
                return (void *)-1;
        }
        SensoryLicense.func = CHIP_WRITE;
        memcpy(&SensoryLicense.buffer, challenge, sizeof(uint32_t) * 2);
        ret = write(fd, &SensoryLicense, sizeof(SensoryLicense));
        if (ret < 0) {
                printf("write %s failed: %s\n", I2C_DEVICE_NAME, strerror(errno));
                return (void *)-1;
        }
        /*
         * userspace prepare a 9 bytes unsigned char array
         * sensory_ic read the 0th bytes for register address
         * then sensory_ic copy respond to 0th of the array
         */
        SensoryLicense.func = CHIP_READ;
        ret = read(fd, &SensoryLicense, sizeof(SensoryLicense));
        memcpy(respond, &SensoryLicense, sizeof(SensoryLicense.buffer));
        if (ret < 0) {
                printf("read %s failed: %s\n", I2C_DEVICE_NAME, strerror(errno));
                return (void *)-1;
        }
        close(fd);
        return respond;
}

program crash after calling getline()

簡單來說

請在getline呼叫之前把lineptr  = null and n = 0這樣最安全

ssize_t getline(char **lineptr, size_t *n, FILE *stream);

如果不小心把 local var 宣告的 char buf[5] = {0}送入了getline

那 getline 有可能因為從 stream 讀到的東西長度大於5,所以 getline 會對 buf 做 realloc

但 buf 是放在 stack 上面的,因為 buf 是 local var

然後就在 stack 上面寫入了 stream 來的資訊,接著process 要拿 stack 的內容出來操作很可能就掛了,例如 stack 裡面寫了 0 ,然後 0 被dereference

Excel Sheet Column Title

題目在這裡

https://oj.leetcode.com/problems/excel-sheet-column-title/

意思是說,輸入一個數字,然後輸出這個數字計算得出的字串,例如:

1->A
2->B
3->C

26->Z
27->AA
28->AB

這個規則乍看之下是個26進位的系統

所以我們可以直接把得到的數字除以26,得到的餘數加上64之後賦值到char變數裡面就是某個對應的字元

例如27除以26得商1餘數1(也就是個位數A),再把商1除以26得到商0餘數1(也就是十位數A)

但是,萬一輸入的數字是26呢?

26除以26得商為1餘數是0,商數1再除以26得到商為0餘數1。

看起來很像是26進位的10

但是

這個系統沒有0這個概念!

而且可以從最上方的舉例很簡單看出來26是Z

我的解法:

除以26之後如果餘數為零,則把商減一,並且直接設定char值為Z。

然後再把減一之後的商(也就是0)繼續除以26,得到商為0,結束。

最簡單的 linked list 範例!

LL 這個概念可以讓程式在處理資料的時候即時的要求記憶體,與之相對的就是 array ,array 在程式執行時會一口氣要求宣告的記憶體數量,沒用到的就浪費了,雖然這個缺點可以利用 realloc 來彌補。BUT!realloc 也必須想辦法知道下一批讀進來的資料量多大才能使用。

#include 
#include 
#include 

struct list{
    int no;
    char cont[50];
    struct list* next;
};
typedef struct list node;

int main(){
    node* head = NULL;
    node* current = NULL;
    node* prev = NULL;
    int no;
    char cont[50];

    while( 1 ){
        printf("no :");
        scanf("%d", &no);
        if( no == 0 )break;
        current = (node*)malloc( sizeof(node) );
        if( current == NULL){
            printf("Errorn");
            return 1;
        }
        current->no = no;
        printf("cont :");
        scanf("%s", cont);
        strncpy(current->cont,cont,49);

        current->next = NULL;
        if(head == NULL){
            head = current;
            prev = current;
        }
        else{
            prev->next = current;
        }
        prev = current;
    }
    //For Display
    current = head;
    while( 1 ){
        printf("%d,%sn", current->no, current->cont);
        if( current->next == NULL)break;
        current = current->next;
    }
    return 0;
}

編譯方法:

gcc -Wall ll.c

linked list 的概念就是把 struct 的東西在每一次需要的時候 malloc 出來,然後利用 struct 裡面的指標指向下一個(當然這邊需要一點判斷,判斷是否為 LL 的頭等等)

如此一來,在使用資料的時候就可以利用指向下一個 struct 的指標來移動目前正在使用的 struct!

本程式執行範例如下:

no :1
cont :abc
no :2
cont :def
no :3
cont :hij
no :4
cont :klm
no :0
1,abc
2,def
3,hij
4,klm

參考資料:
http://blog.xuite.net/coke750101/coketech/20739300

Linux c socket,client,server transfer file with multi-thread,多執行緒傳送檔案

下面程式功能為 server 端可以同時接收多個 client 連上來要求檔案,利用 thread 功能達成『同時、多個』的要求!
使用方法為先執行 server 程式,不要關閉,server 會讀取同一個資料夾底下的 TEST.MP3 這個檔案
然後在同一台機器上面執行 client 並且給予 argv 參數作為存檔的檔名
如果沒有給檔名的話,預設會用 GET.MP3 作為存檔名稱

/*
 * Name : server.c
 * Author : Wen chi-ching
 * Date : 2009/10/15
 * Send file with multi thread
 */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define MAX_THREADS 10

void *thread_function(void *);

int sockfd, new_fd[MAX_THREADS],  res, times=0, i, num=0, *p_num;
socklen_t sin_size;
struct sockaddr_in my_addr;
struct sockaddr_in their_addr;
struct stat filestat;
pthread_t accept_thread[MAX_THREADS];
void *thread_result;

int main(){
	p_num = &num;
	//Get file stat
	if ( lstat("TEST.MP3", &filestat) < 0){
		exit(1);
	}
	printf("The file size is %lun", filestat.st_size);

	//TCP socket
	if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
		perror("socket");
		exit(1);
	}

	//Initail, bind to port 2324
	my_addr.sin_family = AF_INET;
	my_addr.sin_port = htons(2324);
	my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	bzero( &(my_addr.sin_zero), 8 );

	//binding
	if ( bind(sockfd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) == -1 ){
		perror("bind");
		exit(1);
	}

	while(1){
		//Start listening
		if ( listen(sockfd, 10) == -1 ){
			perror("listen");
			exit(1);
		}
		printf("nWait for connectn");
		//Connect
		if ( (new_fd[num] = accept(sockfd, (struct sockaddr*)&their_addr, &sin_size)) == -1 ){
			perror("accept");
			exit(1);
		}

		//Create thread
		res = pthread_create( &(accept_thread[times]), NULL, thread_function, (void *)p_num );
		if (res != 0){
			perror("Thread create failed!n");
			exit(EXIT_FAILURE);
		}
		num++;
		times++;
	}
	close(sockfd);
	return 0;
}

void *thread_function(void *arg){
	int numbytes=0, th_num=0, *p_th_num;
	char buf[1000000];
	FILE *fp;
	p_th_num = (int *)arg;
	th_num = *p_th_num;
	fp = fopen("TEST.MP3", "rb");
	//Sending file
	while(!feof(fp)){
		numbytes = fread(buf, sizeof(char), sizeof(buf), fp);
		printf("thread# is %d : fread %d bytes, ", th_num, numbytes);
		numbytes = write(new_fd[th_num], buf, numbytes);
		printf("Sending %d bytesn",numbytes);
	}
	printf("Sending file Finished!n");
	fclose(fp);
	close(new_fd[th_num]);
	return NULL;
}

server 程式的重點在於 ,因為要同時給多個 client 下載,所以要開 thread ,但是是什麼時間點要開呢?

bind 的時候?listen 的時候?accept 的時候?

其實搞不好都可以。

我選擇在 accept 之後開 thread,並且把 accept 回傳的檔案描述子放到一個陣列去,再把這個陣列的 index 值傳給開出來的 thread ,又,因為 while 裡面有 num++ 的動作,所以每次開 thread 出來的 accept 檔案描述子不會重複,如此也才不會造成 server 傳檔案給 client 的時候檔案指標寫入錯誤的檔案描述子。

整理一下重點,免得自己以後不知道在做啥…

1.accept 的回傳值放到一個 int 陣列去

2.pthread_create 的第四個參數 p_num 存放 num 的址,轉型為 void 是函數的參數型態規定

/*
 * Name : client.c
 * Author : Wen chi-ching
 * Date : 2009/10/14
 * Recieve file
 */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char* argv[]){
	int sockfd, numbytes;
	char buf[1000000],filename[10];
	struct sockaddr_in address;
	FILE *fp;

	//TCP socket
	if ( ( sockfd = socket(AF_INET, SOCK_STREAM, 0) ) == -1 ){
		perror("socket");
		exit(1);
	}

	//Initial, connect to port 2323
	address.sin_family = AF_INET;
	address.sin_port = htons(2324);
	address.sin_addr.s_addr = inet_addr("127.0.0.1");
	bzero( &(address.sin_zero), 8 );

	//Connect to server
	if ( connect(sockfd, (struct sockaddr*)&address, sizeof(struct sockaddr)) == -1){
		perror("connect");
		exit(1);
	}

	//Open file
	if(argc > 1){
		strncpy(filename, argv[1], sizeof(filename) );
	}
	else{
		strncpy(filename, "GET.MP3", sizeof("GET.MP3"));
	}

	if ( (fp = fopen(filename, "wb")) == NULL){
		perror("fopen");
		exit(1);
	}

	//Receive file from server
	while(1){
		numbytes = read(sockfd, buf, sizeof(buf));
		printf("read %d bytes, ", numbytes);
		if(numbytes == 0){
			printf("n");
			break;
		}
		numbytes = fwrite(buf, sizeof(char), numbytes, fp);
		printf("fwrite %d bytesn", numbytes);
		sleep(1);
	}

	fclose(fp);
	close(sockfd);
	return 0;
}

Makefile

all : client.c server.c
	gcc -Wall -g -o client client.c
	gcc -Wall -g -o server server.c -lpthread

clean :
	rm client
	rm server

加入了 #include <arpa/inet.h> 在這兩個程式裡面,解決「implicit declaration of function ‘inet_addr’」這個 warning
int sin_size 改為 socklen_t sin_size;,解決「pointer targets in passing argument 3 of ‘accept’ differ in signedness」這個 warning
2010/07/07

參考:
Linux c socket,client,server transfer file傳送檔案
Linux c socket,client,server.透過網路傳送文字訊息

Linux c socket,client,server transfer file傳送檔案

下面兩隻程式在 linux 利用 socket 來傳送檔案,目前設定為讀取本機端的 TEST.MP3 送到本機端的 GET.MP3
基本上,想要了解這兩隻程式的話,可以先去參考下面兩個連結,先弄懂比較簡單的傳遞文字訊息
然後再來研究傳遞二進位檔案的問題。

socket教學
socket傳遞文字訊息範例

/*
 * Name : server.c
 * Author : Wen chi-ching
 * Date : 2009/10/14
 * Send file
 */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(){
	int sockfd, new_fd, numbytes, sin_size;
	char buf[1000000];
	struct sockaddr_in my_addr;
	struct sockaddr_in their_addr;
	struct stat filestat;
	FILE *fp;

	//TCP socket
	if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
		perror("socket");
		exit(1);
	}

	//Initail, bind to port 2323
	my_addr.sin_family = AF_INET;
	my_addr.sin_port = htons(2324);
	my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	bzero( &(my_addr.sin_zero), 8 );

	//binding
	if ( bind(sockfd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) == -1 ){
		perror("bind");
		exit(1);
	}

	//Start listening
	if ( listen(sockfd, 10) == -1 ){
		perror("listen");
		exit(1);
	}

	//Get file stat
	if ( lstat("TEST.MP3", &filestat) < 0){
		exit(1);
	}
	printf("The file size is %lun", filestat.st_size);

	fp = fopen("TEST.MP3", "rb");

	//Connect
	if ( (new_fd = accept(sockfd, (struct sockaddr*)&their_addr, &sin_size)) == -1 ){
		perror("accept");
		exit(1);
	}

	//Sending file
	while(!feof(fp)){
		numbytes = fread(buf, sizeof(char), sizeof(buf), fp);
		printf("fread %d bytes, ", numbytes);
		numbytes = write(new_fd, buf, numbytes);
		printf("Sending %d bytesn",numbytes);
	}

	close(new_fd);
	close(sockfd);
	return 0;
}

解釋一下 Sending file 的部份:
除非你打算把程式碼寫死成為只能傳送特定大小的檔案,否則,為了讓程式可以傳送任意大小的檔案,我們會在 server 端每次讀取一部分檔案出來傳送,一直讀到檔案結尾為止,所以我們需要一個 while 迴圈,迴圈終止的條件是『fread』讀到檔案結尾。

1.先用 fread 將 fp 開啟的檔案讀到 buf 裡面,讀取 sizeof(char) 大小,sizeof(buf) 次。為避免不同平台可能會有不同 char 大小問題,一定要用 sizeof(char)來寫比較保險。

2.印出目前讀到多少bytes。

3.用 write 將 buf 裡面的資料寫入上面已經連線好了的 new_fd 這個檔案描述子,第三個參數是用來限制要寫入多少 bytes 過去,因為不見得每次都可以把 buf 填滿,例如每次都讀出1M來傳送,則最後通常會有不足1M的剩餘檔案部份需要傳送,所以不能寫 sizeof(buf) ,所以利用 fread 的回傳值來判斷要從 buf 裡面讀出多少來傳送,讀太多的話會送垃圾資訊過去。把傳送過去的大小的值回傳到numbytes裡。

4.印出送了多少 bytes 到遠端。

/*
 * Name : client.c
 * Author : Wen chi-ching
 * Date : 2009/10/14
 * Recieve file
 */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char* argv[]){
	int sockfd, numbytes;
	char buf[1000000];
	struct sockaddr_in address;
	FILE *fp;

	//TCP socket
	if ( ( sockfd = socket(AF_INET, SOCK_STREAM, 0) ) == -1 ){
		perror("socket");
		exit(1);
	}

	//Initial, connect to port 2323
	address.sin_family = AF_INET;
	address.sin_port = htons(2324);
	address.sin_addr.s_addr = inet_addr("127.0.0.1");
	bzero( &(address.sin_zero), 8 );

	//Connect to server
	if ( connect(sockfd, (struct sockaddr*)&address, sizeof(struct sockaddr)) == -1){
		perror("connect");
		exit(1);
	}

	//Open file
	if ( (fp = fopen("GET.MP3", "wb")) == NULL){
		perror("fopen");
		exit(1);
	}

	//Receive file from server
	while(1){
		numbytes = read(sockfd, buf, sizeof(buf));
		printf("read %d bytes, ", numbytes);
		if(numbytes == 0){
			break;
		}
		numbytes = fwrite(buf, sizeof(char), numbytes, fp);
		printf("fwrite %d bytesn", numbytes);
	}

	fclose(fp);
	close(sockfd);
	return 0;
}

解釋一下 Receive file from server 的部份:
所以這邊跟 server 都同樣會需要一個 while 迴圈,控制迴圈結束的條件是『接收到大小為零』,這代表檔案已經傳送完了!

1.用 read 將上面已經連線了的 sockfd 檔案描述子的內容讀取到 buf 裡面,每次最多寫入 sizeof(buf) bytes。將回傳值存在 numbytes 這個變數裡,下兩行的寫檔會需要這個數值。

2.印出本次 read 接收到了多少 bytes 。

3.如果接收到的 bytes 為零的話就結束迴圈,因為我們認為這樣的條件代表檔案傳送完了。

4.用 fwrite 將 buf 的資料寫入 fp ,每次寫入 sizeof(char) bytes,寫入 numbytes 次,寫入太多的話會寫入垃圾資訊,所以要用剛才 read 的回傳值來控制要寫入多少 bytes。

5.印出本次 fwrite 寫入了多少 byets 。

Makefile

all : client.c server.c
	gcc -Wall -g -o client client.c
	gcc -Wall -g -o server server.c

clean :
	rm client
	rm server

輸入 make 即可編譯,不過可能會出現一點警告,可以暫時不用理他。

lstat 取得檔案大小

在使用 socket 程式傳送檔案的時候,會需要傳遞檔案大小這個變數,以下是一個 c 語言取得檔案大小的範例。

#include 
#include 
#include 
#include 
#include 

int main(){
	FILE *fp;
	struct stat buf;
	if ( (fp = fopen("TEST.MP3", "rb")) == NULL){
		perror("fopen");
		exit(1);
	}
	if ( lstat("TEST.MP3", &buf) < 0 ){
		return 1;
	}
	printf("The file size of TEST.MP3 is %lu bytesn", buf.st_size);
	return 0;
}

編譯方法:

gcc -Wall -o size size.c

lstat 的說明:
參考資料1
參考資料2 (ˇ推薦閱讀)

直接執行 ./size 就可以看到 TEST.MP3 這個檔案的大小了,單位為 bytes 。

另外,fstat 和 stat 跑出來的值都不太對,原因尚待釐清= =a

Linux c socket,client,server.透過網路傳送文字訊息

下面的程式將可以透過 client 程式將 “hello!" 送到遠端機器的 server 程式,兩邊的 IP 目前是寫死到 code 裡面,這部份也可以簡單利用 argv 從 command line 下參數。

socket 的東西很多,這篇文章是當作筆記提醒自己用的。

/*
 * Name : client.c
 * Author : Wen chi-ching
 * Date : 2009/10/11
 */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char* argv[]){
	int sockfd, numbytes;
	char buf[100];
	struct sockaddr_in address;

	//TCP socket
	if ( ( sockfd = socket(AF_INET, SOCK_STREAM, 0) ) == -1 ){
		perror("socket");
		exit(1);
	}

	//Initial, connect to port 2323
	address.sin_family = AF_INET;
	address.sin_port = htons(2323);
	address.sin_addr.s_addr = inet_addr("127.0.0.1");
	bzero( &(address.sin_zero), 8 );

	//Connect to server
	if ( connect(sockfd, (struct sockaddr*)&address, sizeof(struct sockaddr)) == -1){
		perror("connect");
		exit(1);
	}

	//Send "Hello";
	if ( (numbytes = write(sockfd, "hello!", strlen("hello!")) )== -1 ){
		perror("send");
		exit(1);
	}
	printf("Write %d bytes , ",numbytes);

	//Receive from server
	if ( (numbytes = read(sockfd, buf, strlen(buf)) ) == -1 ){
		perror("recv");
		exit(1);
	}
	printf("Read %d bytesn",numbytes);
	buf[numbytes] = '';
	printf("result: %s n", buf);
	close(sockfd);
	return 0;
}
/*
 * Name : server.c
 * Author : Wen chi-ching
 * Date : 2009/10/11
 */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(){
	int sockfd, new_fd, numbytes;
	struct sockaddr_in my_addr;
	struct sockaddr_in their_addr;
	int sin_size;
	char buf[100];

	//TCP socket
	if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
		perror("socket");
		exit(1);
	}

	//Initail, bind to port 2323
	my_addr.sin_family = AF_INET;
	my_addr.sin_port = htons(2323);
	my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	bzero( &(my_addr.sin_zero), 8 );

	//binding
	if ( bind(sockfd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) == -1 ){
		perror("bind");
		exit(1);
	}

	//Start listening
	if ( listen(sockfd, 10) == -1 ){
		perror("listen");
		exit(1);
	}

	//Wait for connect!
	while(1){
		sin_size = sizeof(struct sockaddr_in);
		perror("server is run");
		if ( (new_fd = accept(sockfd, (struct sockaddr*)&their_addr, &sin_size)) == -1 ){
			perror("accept");
			exit(1);
		}

		if ( !fork() ){
			//Receive
			if ( (numbytes = read(new_fd, buf, sizeof(buf))) == -1 ){
			  	perror("recv");
				exit(1);
			}
			printf("Receive %d bytes , ", numbytes);
			printf("%sn", buf);
			//Send back
			if ( (numbytes = write(new_fd, buf, strlen(buf))) == -1){
				perror("send");
				exit(0);
			}
			printf("Send %d bytes , ", numbytes);
			printf("%sn", buf);
			close(new_fd);
		}
	}
	close(sockfd);
	return 0;
}

Makefile

all : client.c server.c
	gcc -Wall -g -o client client.c
	gcc -Wall -g -o server server.c

clean :
	rm client
	rm server

把上面三份程式碼(兩份 c ,一份 Makefile),下載下來之後,輸入 make 就可以了,正常而言會編譯出兩個執行檔。加上 -g 是為了玩 gdb 而加上去的

又,因為目前 IP 是設定為本機 127.0.0.1 ,所以可以先直接在本機上面執行 server ,再執行 client 就可以看到結果了。

http://www.linuxhowtos.org/C_C++/socket.htm – Linux socket 教學
http://linux.die.net/ – Linux 指令查詢,可以用來查函數的參數詳細內容、規格等等