在unix下寫(xiě)socket程序可能是最方便,你只要掌握其一般步驟,就可以松的寫(xiě)出面向傳輸層的應(yīng)用。
1、
理解幾個(gè)常用的socket函數(shù) #include
#include
int socket(int domain,int type,int portocol);
domain指所使用的協(xié)議族(family)可以為AF_UNIX和AF_INET,一般只用AF_INET(指Internet)type指所用的傳輸類型,可以為SOCK_STERAM(面向連接的TCP),和SOCK_DGRAM(面向無(wú)連接的udp)
int bind(int s,const struct sockaddr *address,size_t address_len);
s為socket返回的文件描述符
address為協(xié)議族名稱和其他信息
具體結(jié)構(gòu)為struct sockaddr_in{
short sin_family;/*協(xié)議族
u_short sin_port;/*端口*/
struct in_addr sin_addr;/*地址*/
char sin_zero[8];
};
int listen(int s,int backlog);
backlog為容許的請(qǐng)求數(shù)目
int accept(int s,struct sockaddr *address,int *address_len);
這里的前兩個(gè)參數(shù)同上
addres_len是要傳遞一個(gè)記有結(jié)構(gòu)大小的地址
int connect(int s,struct sockaddr *address,size_t address_len);
這里的參數(shù)意義同bind
2.理解建立程序的一般調(diào)用過(guò)程
要建立一個(gè)處理連接的服務(wù)器端程序,首先要調(diào)用socket函數(shù)創(chuàng)建一個(gè)socket,返回一個(gè)文件句柄fd,使以后對(duì)它的操作就象對(duì)普通文件設(shè)備一樣讀寫(xiě)。
由于是服務(wù)器端必須對(duì)一個(gè)斷口進(jìn)行監(jiān)聽(tīng)其他機(jī)器的請(qǐng)求,所以接下去調(diào)用bind函數(shù),傳入剛才的fd,定義好地址和端口,由于是要接受來(lái)自任何host的連接所以應(yīng)講sin_addr賦為INADDR_ANY,port為你所設(shè)定的端口。
注意:這里的地址和端口是網(wǎng)絡(luò)字節(jié)順序,所以要調(diào)用htonl,htons完成主機(jī)字節(jié)順序
到網(wǎng)絡(luò)字節(jié)的轉(zhuǎn)變
接下來(lái)就是監(jiān)聽(tīng)listen,調(diào)用accept接受來(lái)自客戶端的請(qǐng)求,accpet返回連接后的文件描述符,你就可以用它進(jìn)行收發(fā)信息(對(duì)應(yīng)于read,write)這樣的一個(gè)過(guò)程就是socket->bind->listen->accpet->Read,write
而對(duì)于客戶端則是socket->connect->read,write
3.一個(gè)完整的程序
#include?
#include?

#include?/**//*包含有htons等函數(shù)的頭文件*/

#include?
#include?

void?main()

{
int?listenfd,clifd;
long?pid;
struct?sockaddr_in?myaddr,cliaddr;

int?ret;
int?len;

listenfd=socket(AF_INET,SOCK_STREAM,0);
if?(listenfd<0)

{
perror("socket?error");
exit(-1);
}

myaddr.sin_family=AF_INET;
myaddr.sin_addr.s_addr=htonl(INADDR_ANY);
myaddr.sin_port=htons(8888);

ret=bind(listenfd,(struct?sockaddr?*)&myaddr,sizeof(myaddr));
if?(ret<0)

{
perror("bind?error");
exit(-1);
}
listen(listenfd,10);
len=sizeof(struct?sockaddr);
while(1)

{
clifd=accept(listenfd,(struct?sockaddr*)&cliaddr,&len);

?/**//*注意accept的第三個(gè)參數(shù)也是地址*/
if(clifd==-1)

{
perror("accept?error");
continue;
}
printf("connect?from?%s?%d?",inet_ntoa(cliaddr.sin_addr.s_addr),ntohs(cliaddr.sin_port));

switch(pid=fork())

{

case?0:?/**//*子進(jìn)程*/
close(listenfd);

;/**//*子進(jìn)程進(jìn)行其他的操作*/
close(clifd);
exit(0);
break;
case?-1:
perror("fork?error");
break;

default:/**//*父進(jìn)程*/
close(clifd);
break;

}
}

}

4.程序說(shuō)明
該程序的功能是監(jiān)聽(tīng)8888端口的連接,對(duì)所有的對(duì)8888端口的連接顯示出地址和對(duì)方的端口號(hào)該程序在sco unix下調(diào)試通過(guò),在其他unix和linux平臺(tái)請(qǐng)注意inet_ntoa,htons函數(shù)所應(yīng)在的頭文件的名稱
同時(shí)該程序用到了并發(fā)的觀點(diǎn),因?yàn)閍ccept,read,write均為阻塞(block)的函數(shù),一旦進(jìn)程block將不能處理其他請(qǐng)求,所以用主進(jìn)程進(jìn)行l(wèi)isten,由子進(jìn)程進(jìn)行負(fù)責(zé)對(duì)客戶端傳輸數(shù)據(jù).
你可以在同一臺(tái)unix機(jī)器用telnet localhost 8888進(jìn)行觀察程序會(huì)輸出connect from 127.0.0.1 xxxx