青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

牽著老婆滿街逛

嚴以律己,寬以待人. 三思而后行.
GMail/GTalk: yanglinbo#google.com;
MSN/Email: tx7do#yahoo.com.cn;
QQ: 3 0 3 3 9 6 9 2 0 .

socket編程—技術實現

這幾天都在玩socket了,有一點心得,貼出來與大家共賞,若有不妥或錯誤的地方,還請各位看官指點一二。

什么是socket?socket就是...,我在這里就不抄書了,有興趣的同仁去查查書吧。
不過還要說一句,socket就是不同進程之間的一種通信方式。就象打電話是朋友之間的一種通信方式是一樣。個人理解:所謂“通信”,就是相互之間發送數據。有人理解socket是不同計算機之間的一種通信方
式,這是不確切的。兩個進程,不管是運行在同一臺計算機上,還是運行在不同計算機上,都可通過
socket技術進行通信。

socket套接字的使用需要有網卡的支持,所以socket一般都被用來在不同機器之間通信,而如果在同一臺計算機上的兩個進程進行通信,通常采用效率更高的共享內存技術來實現。

兩個進程之間進行通訊,就需要兩個進程同時都在運行了(廢話),在具體實現中,兩個進程我們通常要區別對待,一個進程專門等待另一個進程給自己發消息,收到消息后進行處理,在把處理結果發送回去。我們把專門處理消息、提供服務的進程稱為服務器端,把發送消息、請求處理的進程稱為客戶端??傮w過程就是客戶端發送一個消息給服務器端,服務器端進程收到消息進行處理,把處理結果發送給客戶端。恩,就是這樣。

還有一個問題,如果我現在有一個進程要跟另一臺計算機上的某個進程進行socket通信,那在我這個進程中如何指定另一個進程呢?這里還需要說一下另一個概念——端口,如果把操作系統比作一座房子的話,那端口就是房子的窗口,是系統外界同系統內部進行通信的通道。在socket實現中,我們不進行另一個進程的指定,而是指定發送消息或接收消息的端口號。比如說現在進程A要給進程B發消息,我們會把消息發送到進程B所運行的計算機的端口N上,而進程B此時正在監視端口N,這樣進程B就能收到進程A發送來的數據,同樣進程B也把消息發送到該端口上,進程A也能從該端口收到進程B發送來的數據,當然,這需要客戶端和服務器端關于端口號進行一個約定,即共同操作同一個端口。如果客戶端把消息發送到端口N1上,而服務器端監視的是端口N2,那通信一定不能成功。端口號最大為65535,不能比這個再大了,但在我們自己的程序中盡量不要用小于1024的端口號,小于1024的端口好很多都被系統使用了,比如23被telnet所使用。

socket的實現是很簡單的,只要按照一定的步驟,就可馬上建立一個這樣的通信通道。

下面較詳細的介紹幾個核心的函數:

SOCKET socket(int af, int type, int protocol);
無論是客戶端還是服務器端,下面這個函數是一定要用到的,也是最先用到的。
這個函數是要告訴系統,給我準備好一個socket通道,我要和其它進程通信了。函數的返回值很重要,我們要記下來,它表示系統為我們準備好的這個socket通道,在以后的每個socket相關函數中都會用到,如果這個值等于SOCKET_ERROR,表示函數執行失敗了。函數的參數我們分別給:PF_INET、SOCK_STREAM和IPPROTO_TCP。

int bind(SOCKET s, const sockaddr *addr, int namelen);
這個函數只有服務器端程序使用,作用是與某個socket通道綁定。可以用返回值判斷該函數執行結果怎么樣,如果等于SOCKET_ERROR,那就是失敗了。第一個參數s,就是socket()函數的返回值;在結構addr中,我們要給定一個端口號;namelen等于結構sockaddr的大小。

int listen(SOCKET s, int backlog);
這個函數只有服務器端程序使用,作用是監聽該端口。返回值與bind函數意義一樣。

int accept(SOCKET s, sockaddr *addr, int *addrlen);
這個函數只有服務器端程序使用,作用是響應客戶端的連接。返回值與bind函數意義一樣。

int connect(SOCKET s, const sockaddr *name, int namelen);
這個函數只有客戶端程序使用,作用是把客戶端和某個計算機的某個端口建立連接。返回值與bind函數意義一樣。第一個參數s,就是socket()函數的返回值;在結構name中,我們要給定一個端口號和目的機器名;namelen等于結構sockaddr的大小。

int send(SOCKET s, char *buf, int len, int flags);
int recv(SOCKET s, char *buf, int len, int flags);
這兩個函數就是發送數據和接收數據,客戶端和服務器端程序都能用,哪個發送哪個接收不用說了吧?呵呵。
從函數的返回值可以檢查函數執行是否成功。參數中buf是指向發送或接收的數據的指針,len是數據長度。flags我們給個0就可以(其實是我不知道具體含義)。

最后就是關閉socket了,這個很容易忘掉,但這個函數很重要,一定要用。
int closesocket(SOCKET s);


好了,關鍵函數就這么幾個,下圖是這幾個函數的執行順序:

client端 service端

? | ? ? |
? v ? ? v
socket() socket()
? | ? ? |
? | ? ? v
? | ? bind()
? | ? ? |
? | ? ? v
? | ? listen()
? | ? ? |
? | ? ? v
? | ? accept() 掛起,直到有客戶端來連接
? | ? ? |
? v ? 三段握手過程 ? |
connect() <-------------> |
? | ? ? |
? v ? 發送消息 ? v
? +---> send() ---------------> recv() <-------+
? | ? | ? ? . |
? | ? | ? ? . 處理消息 |
? | ? v ? 響應消息 ? . |
? +---- recv() <--------------- send() --------+
? | ? ? |
? v ? ? |
close() ---------------> recv()
? ? |
? ? v
? closesocket()

上圖我覺得能很好的說明客戶端和服務器端的運行軌跡。

使用以上幾個函數在 linux 系統上就可成功建立一個socket通信連路,但如果在windows系統上,還要用到另一個函數:
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
在windows系統上,首先要執行這個函數,所以要把這個函數放在socket()函數的前面。

我對上面的函數進行了一些封裝,為節省篇幅,我去掉所有注釋和非重要的函數,在這里可以看到各個函數的具體用法:

在 VC60 環境下要運行下面的函數,要包含頭文件 errno.h 和 winsock2.h,還有,在連接的時候要連接上ws2_32.dll文件。

這是頭文件內容:
class Socket {
public:

bool setup();

void close();

bool connect(string host, int port);

bool listen();

int accept();

int recv(char *buf, int len);

int recv(int new_fd, char *buf, int len);

int send(const char *msg, int len);

int send(int new_fd, const char *msg, int len);

private:
? int _fd;
};

這是實現文件內容:
bool Socket::setup() {

WSADATA wsd;
_fd = WSAStartup(MAKEWORD(2,2), &wsd);
if(_fd) {
return false;
}

_fd = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (_fd == -1) {
return false;
}
return true;
}

bool Socket::listen() {
struct sockaddr_in my_addr;

my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(52309);
my_addr.sin_addr.s_addr = INADDR_ANY;

if(::bind(_fd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == SOCKET_ERROR) {
return false;
}

if(::listen(_fd, BACKLOG) == SOCKET_ERROR) {
return false;
}

return true;
}

int Socket::accept()
{
int new_fd;
struct sockaddr_in their_addr;
int sin_size = sizeof(their_addr);

printf("accepting... \n");

new_fd = ::accept(_fd,
? (struct sockaddr *)&their_addr,
? &sin_size);
return new_fd == SOCKET_ERROR ? -1:new_fd;
}

bool Socket::connect(string host, int port) {
struct hostent *_h = gethostbyname(host.c_str());
if (_h == 0) {
return false;
}

struct in_addr *_addr = (struct in_addr *)_h->h_addr;
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr = *_addr;
sin.sin_port = htons(port);

if (::connect(_fd, (sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR) {
return false;
}

return true;
}

int Socket::recv(int new_fd, char *buf, int len)
{
int nb = ::recv(new_fd, buf, len, 0);
if (nb == -1) {
printf("Error! recv.\n");
}
return nb;
}

int Socket::recv(char *buf, int len) {
return recv(_fd, buf, len);
}

int Socket::send(const char *msg, int len) {
return send(_fd, msg, len);
}

int Socket::send(int new_fd, const char *msg, int len)
{
int nb = ::send(new_fd, msg, len, 0);
if (nb == -1) {
printf("Error! send.\n");
}

return nb;
}

void Socket::close() {

int trytimes = 0;
while(::closesocket(_fd) && trytimes < CLOSE_TRY_TIMES)
trytimes++;

if(trytimes == 10) {
printf("Cannot close socket!\n");
}
}

好,socket類是封裝好了,下面就是組織了,服務器端和客戶端是不一樣的,下面分別給出代碼,到這里已經就很簡單了。

客戶端:
int main(int argc, char **argv)
{
printf("socket of client is run ...\n");
Socket s;
if (!s.connect("dezhi", 52309))
return 0;

char *msg = "ok, send a message.";
for (int i=0; i<10; i++) {
s.send(msg, 20);
printf("message = %s\n", msg);
}
s.send("q", 1);
s.close();

return 0;
}

服務器:
int main(int argc, char **argv) {
printf("socket of service is run ...\n");

Socket s;
s.listen();
int new_fd = s.accept();

char buf[8];
buf[7] = '\0';
while (1) {
if (s.recv(new_fd, buf, 5) != -1) {
? printf("%s\n", buf);
? if (buf[0] == 'q')
? break;
}
}
s.close();
}

下面為運行結果:
客戶端:
socket of client is run ...
Socket: WSAStartup success execute.
Socket: socket success execute.
Socket: Establish the connection to "127.0.0.1:52309"
message = ok, send a message.
message = ok, send a message.
message = ok, send a message.
message = ok, send a message.
message = ok, send a message.
message = ok, send a message.
message = ok, send a message.
message = ok, send a message.
message = ok, send a message.
message = ok, send a message.
Socket: Close connection to "127.0.0.1:52309"
Press any key to continue

服務器端
socket of service is run ...
Socket: WSAStartup success execute.
Socket: socket success execute.
bind ok!
listen ok!
accepting...
ok, send a message.
ok, send a message.
ok, send a message.
ok, send a message.
ok, send a message.
ok, send a message.
ok, send a message.
ok, send a message.
ok, send a message.
ok, send a message.
qk, send a message.
Press any key to continue

就到這里吧。socket的相關內容可遠不止這些,我在這里只是給大家來個拋磚引玉,想深究?路還很漫長。關于詳細的實現代碼,去我的《源碼》上找吧,不放在這里,是為了讓篇幅小些。

posted on 2006-04-20 17:36 楊粼波 閱讀(905) 評論(0)  編輯 收藏 引用 所屬分類: 網絡編程

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美成人精品在线视频| 在线观看一区视频| 久久亚洲风情| 久久久精品2019中文字幕神马| 性欧美video另类hd性玩具| 欧美一区二区在线看| 久久精品视频亚洲| 欧美电影打屁股sp| 国产精品xvideos88| 国产一区导航| 亚洲精品你懂的| 午夜国产精品视频| 免费一级欧美片在线观看| 亚洲精品美女在线观看| 亚洲色图综合久久| 久久精品72免费观看| 欧美日韩国产精品| 国产在线高清精品| 夜夜夜久久久| 欧美+亚洲+精品+三区| 一区二区成人精品| 久久精品亚洲乱码伦伦中文 | 91久久极品少妇xxxxⅹ软件| 艳女tv在线观看国产一区| 欧美一区国产二区| 欧美日韩国产小视频| 狠狠色丁香婷婷综合久久片| 在线视频亚洲一区| 巨乳诱惑日韩免费av| 一区二区三区视频在线| 久久久久久久综合色一本| 欧美日韩亚洲激情| 亚洲国内高清视频| 久久中文字幕导航| 亚洲欧美影音先锋| 欧美视频日韩视频| 亚洲免费观看在线观看| 麻豆精品在线视频| 欧美一区成人| 国产嫩草影院久久久久 | 亚洲一区精品电影| 亚洲国产天堂久久综合网| 欧美亚洲色图校园春色| 欧美性大战久久久久久久| 99视频在线观看一区三区| 欧美福利视频一区| 久久亚洲精选| 樱花yy私人影院亚洲| 久久久www成人免费无遮挡大片| 一本久久综合亚洲鲁鲁| 欧美日韩综合在线| 一本色道久久99精品综合| 亚洲电影在线看| 蜜桃av一区二区三区| 亚洲国产精品久久久| 亚洲大胆av| 久久久99免费视频| 欧美在线在线| 伊人久久婷婷| 亚洲第一毛片| 欧美日本精品一区二区三区| 宅男噜噜噜66一区二区66| 一本色道88久久加勒比精品 | 亚洲国产欧美国产综合一区| 免费h精品视频在线播放| 久久精品一区二区三区中文字幕| 狠狠88综合久久久久综合网| 美女精品视频一区| 女仆av观看一区| 亚洲另类自拍| 99综合电影在线视频| 国产精品美女黄网| 久久欧美中文字幕| 免费视频亚洲| 亚洲女ⅴideoshd黑人| 午夜精品国产更新| 亚洲第一中文字幕在线观看| 91久久国产综合久久91精品网站| 欧美日韩一区二区三区四区五区 | 亚洲免费黄色| 国产老肥熟一区二区三区| 久久久无码精品亚洲日韩按摩| 久久久久久综合| 日韩一区二区免费高清| 亚洲午夜精品17c| 在线精品高清中文字幕| 99精品欧美一区二区蜜桃免费| 国产网站欧美日韩免费精品在线观看 | 亚洲欧美日韩国产成人| 久久国产精品一区二区| 99国产精品久久| 性久久久久久久久久久久| 亚洲国产精品小视频| 亚洲视屏在线播放| 亚洲国产欧美一区| 亚洲欧美日韩精品| 日韩亚洲欧美一区二区三区| 欧美亚洲综合另类| 亚洲一区二区三区高清不卡| 久久青青草原一区二区| 性欧美暴力猛交69hd| 欧美国产日韩精品| 久久人人97超碰精品888| 国产精品国产a级| 欧美成人精品在线播放| 国产日韩精品一区二区| aa级大片欧美三级| 亚洲精品久久久久久久久久久| 亚洲伊人网站| 在线视频你懂得一区| 欧美99在线视频观看| 一区二区三区日韩在线观看| 亚洲国产成人高清精品| 国产日韩在线看片| 99精品久久免费看蜜臀剧情介绍| 精品成人在线观看| 欧美亚洲日本国产| 欧美一级大片在线免费观看| 欧美日韩黄色大片| 亚洲第一天堂av| 亚洲国产成人久久| 欧美专区在线观看| 久久久久久尹人网香蕉| 国产在线观看91精品一区| 欧美一区二区三区啪啪| 久久超碰97人人做人人爱| 国产精品视频一| 在线视频精品一| 亚洲欧美电影在线观看| 国产精品男女猛烈高潮激情| 亚洲社区在线观看| 亚洲欧美日韩综合一区| 国产精品久久一区二区三区| 一区二区三区欧美日韩| 亚洲女女女同性video| 国产精品美女主播| 亚洲欧美日韩精品| 久久精品视频亚洲| 亚洲高清激情| 欧美极品aⅴ影院| 一区二区国产精品| 欧美一区影院| 国产综合久久久久久鬼色| 久久久久久久尹人综合网亚洲| 欧美成人首页| 中国女人久久久| 国产日韩欧美| 美女国产一区| 99国产精品99久久久久久| 亚洲欧美日韩国产中文在线| 国产婷婷色一区二区三区| 久久亚洲综合色| 亚洲精品少妇| 欧美一区二区在线免费观看| 激情av一区二区| 欧美精品www| 午夜欧美不卡精品aaaaa| 男女视频一区二区| 一区二区三区毛片| 国产精品揄拍500视频| 久久九九电影| 日韩手机在线导航| 久久久久久久网站| 99爱精品视频| 狠狠色2019综合网| 欧美日韩国产在线播放网站| 性娇小13――14欧美| 亚洲国产网站| 久久久久久网址| 一区二区三区欧美在线| 国产日产亚洲精品系列| 欧美黄色一级视频| 午夜精品在线观看| 亚洲日本中文字幕| 另类尿喷潮videofree| 亚洲午夜极品| 亚洲精品1区| 国产欧美日韩视频一区二区| 欧美韩国一区| 久久久蜜桃精品 | 久久精品一区二区三区中文字幕 | 久久福利电影| 日韩视频在线一区| 国产综合视频| 国产精品久久久久久久久久妞妞| 欧美在线视频观看免费网站| 亚洲人体1000| 母乳一区在线观看| 久久精品午夜| 欧美一区二区在线| 亚洲小视频在线观看| 亚洲激情在线激情| 韩国在线视频一区| 国产精品久久久久久五月尺| 欧美成人一二三| 老司机免费视频久久| 久久精品99国产精品酒店日本| 亚洲午夜影视影院在线观看| 亚洲乱码精品一二三四区日韩在线 | 麻豆精品视频|