?? 基本tcp套接口編程一.txt
字號(hào):
基本TCP套接口編程一
--------------------------------------------------------------------------------
第八軍團(tuán) 時(shí)間:2004-1-17 21:36:52
概述
socket() --得到文件描述符!
bind() --我們?cè)谀膫€(gè)端口?
connect() --Hello!
listen() --有人給我打電話嗎?
accept() --"Thank you for calling port 3490."
send() 和 recv() --Talk to me, baby!
sendto() 和 recvfrom() --Talk to me, DGRAM-style
close() 和 shutdown() --滾開!
getpeername() --你是誰?
gethostname() --我是誰?
DNS --你說“白宮”,我說 "198.137.240.100"
--------------------------------------------------------------------------------
socket函數(shù)
功能:指定協(xié)議類型
定義:
#include <sys/types.h>
#include <sys/socket.h>
int socket(int family, int type, int protocol);
返回值
出錯(cuò): -1
成功: 套接口描述字 (socket file descriptor)(套接字)sockfd
socket 函數(shù)指定了協(xié)議族(IPv4、IPv6或unix)和套接口類型(字節(jié)流、數(shù)據(jù)報(bào)或原
始套接口)。但并沒有指定本地協(xié)議地址或遠(yuǎn)程協(xié)議地址。
理解socket
socket使用 Unix 文件描述符 (file descriptor) 和其他程序通訊的方式。
Unix 程序在執(zhí)行任何形式的 I/O 的時(shí)候,程序是在讀或者寫一個(gè)文件描述符。
一個(gè)文件描述符只是一個(gè)和打開的文件相關(guān)聯(lián)的整數(shù)。
這個(gè)文件可能是一個(gè)網(wǎng)絡(luò)連接,F(xiàn)IFO,管道,終端,磁盤上的文件或者什么其他
的東西。Unix 中所有的東西是文件!因此,與 Internet 上別的程序通訊的時(shí)候,
要通過文件描述符。利用系統(tǒng)調(diào)用 socket()得到網(wǎng)絡(luò)通訊的文件描述符。他返回
套接口描述符 (socket descriptor),然后再通過他來調(diào)用 send() 和 recv()。
那么為什么不用一般的調(diào)用 read() 和 write() 來通過套接口通訊?
簡(jiǎn)單的答案是:可以使用一般的函數(shù)!
詳細(xì)的答案是:使用 send() 和 recv() 讓你更好的控制數(shù)據(jù)傳輸。
--------------------------------------------------------------------------------
connect 函數(shù)
功能:建立與TCP服務(wù)器的連接
定義:
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
//sockfd 是系統(tǒng)調(diào)用 socket() 返回的套接口文件描述符
serv_addr 是保存著目的地端口和 IP 地址的數(shù)據(jù)結(jié)構(gòu) struct sockaddr
//addrlen 設(shè)置為 sizeof(struct sockaddr)
connect 激發(fā) TCP的三路握手過程
服務(wù)器必須準(zhǔn)備好接受外來的連接。
這通過調(diào)用socket,bind和1isten函數(shù)來完成,稱為被動(dòng)打開(Passive open)
客戶通過調(diào)用connect進(jìn)行主動(dòng)打開(active opn)。
這引起客戶TCP發(fā)送一個(gè)SYN分節(jié)(表示同步),它告訴服務(wù)器客戶將在(待建立的)
連接中發(fā)送的數(shù)據(jù)的初始序列號(hào)。
服務(wù)器必須確認(rèn)客戶的SYN,同時(shí)自己也得發(fā)送一個(gè)SYN分節(jié),它含有服務(wù)器將在
同一連接中發(fā)送的數(shù)據(jù)的韌始序列號(hào)。服務(wù)器以單個(gè)分節(jié)向客戶發(fā)送SYN和對(duì)客戶
SYN的ACK。客戶必須確認(rèn)服務(wù)器的SYN。
connect 出錯(cuò)時(shí)的返回
出錯(cuò)原因 :未收到SYN的響應(yīng)(服務(wù)器超時(shí),75s)
返回值:ETIMEDOUT
用戶端輸出:Connection time out.
出錯(cuò)原因 :收到RST響應(yīng)(Hard error)SYN到達(dá)服務(wù)器,但該服務(wù)器的無此項(xiàng)端口服務(wù)
返回值:ECONNREFUSE
用戶端輸出:Connection refused
出錯(cuò)原因 :ICMP錯(cuò)誤:不可路由(soft error)(目的地不可達(dá))
返回值:EHOSTUNREACH
用戶端輸出:ENETUNREACH No route to host
--------------------------------------------------------------------------------
bind 函數(shù)
功能:給套接口分配一個(gè)本地協(xié)議地址
定義:
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *my_addr, int addrlen);
sockfd 是調(diào)用 socket 返回的文件描述符。
my_addr 是指向數(shù)據(jù)結(jié)構(gòu) struct sockaddr 的指針,保存地址(即端口和 IP 地址) 信息。
addrlen 設(shè)置為 sizeof(struct sockaddr)。
返回: 0—成功, -1---出錯(cuò)
讓內(nèi)核自動(dòng)處理地址ip和端口port
my_addr.sin_port = 0; /* choose an unused port at random */
my_addr.sin_addr.s_addr = INADDR_ANY; /* use my IP address */
bind( ) 自己選擇合適的端口:將0賦給 my_addr.sin_por。
自動(dòng)填上他所運(yùn)行的機(jī)器的 IP 地址:my_addr.sin_addr.s_addr 設(shè)置為 INADDR_ANY。
--------------------------------------------------------------------------------
listen 函數(shù)
功能:將未連接主動(dòng)套接口的轉(zhuǎn)換為被動(dòng)套接口,指示內(nèi)核接受對(duì)該套接口的連接請(qǐng)求.
CLOSED --? LISTEN
定義:
#include <sys/socket.h>
int listen(int sockfd, int backlog);
sockfd 是調(diào)用 socket() 返回的套接口文件描述符。
backlog 是在進(jìn)入隊(duì)列中允許的連接數(shù)目。
監(jiān)聽套接口的兩個(gè)隊(duì)列
未完成連接隊(duì)列(incompleted connection queue): SYN_RECV
已完成連接隊(duì)列(completed connection queue): ESTABLISHED
當(dāng)一個(gè)客戶的SYN到達(dá)時(shí),如兩隊(duì)列都滿的, TCP將忽略該分節(jié)且不發(fā)RST
--------------------------------------------------------------------------------
ACCEPT 函數(shù)
功能:在已完成隊(duì)列頭返回下一個(gè)已完成的連接
定義
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *cliaddr, int* addrlen);
調(diào)用成功時(shí)返回: 1. cliaddr: 客戶進(jìn)程的協(xié)議地址和地址大小 2. 新套接口描述字
(已連接套接口描述字)
監(jiān)聽套接口描述字 listening socket descriptor
一個(gè)給定的服務(wù)器常常是只生成一個(gè)監(jiān)聽套接口, 且一直存在,直到該服務(wù)器關(guān)閉。
已連接套接口描述字connected socket descriptor
內(nèi)核為每個(gè)被接受的客戶連接創(chuàng)建了一個(gè)已連接套接口。當(dāng)服務(wù)器完成某客戶的服務(wù)時(shí),
關(guān)閉已連接套接口。
1024以下的端口:超級(jí)用戶使用
--------------------------------------------------------------------------------
fork 函數(shù)
功能:派生新進(jìn)程 create new process
定義:
#include <sys/unistd.h>
pid_t fork (void);
在子進(jìn)程中返回0,在父進(jìn)程中返回子進(jìn)程的進(jìn)程ID
出錯(cuò)時(shí)返回 –1,調(diào)用一次返回兩次
fork的典型應(yīng)用:
1.一個(gè)進(jìn)程可為自己創(chuàng)建一個(gè)拷貝。當(dāng)一個(gè)拷貝處理一個(gè)操作時(shí),其他的拷貝可以
執(zhí)行其他的任務(wù)。這是非常典型的網(wǎng)絡(luò)服務(wù)器。
2.一個(gè)進(jìn)程想執(zhí)行其他的程序,由于創(chuàng)建新進(jìn)程的唯一方法是調(diào)用fork,進(jìn)程首先
調(diào) 用fork來生成一個(gè)拷貝,然后其中一個(gè)拷貝(通常為子進(jìn)程)調(diào)用exec 來代替自己
去執(zhí)行新程序。
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -