Socket编程实践(3) --Socket API
socket函數
#include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol);創建一個套接字用于通信
參數:
? ?domain:指定通信協議族(protocol?family),常用取值AF_INET(IPv4)
? ?type:指定socket類型,?流式套接字SOCK_STREAM,數據報套接字SOCK_DGRAM,原始套接字SOCK_RAW
? ?protocol:協議類型,常用取值0,?使用默認協議
返回值:
? ?成功:?返回非負整數,套接字;
? ?失敗:?返回-1
bind函數
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);綁定一個本地地址到套接字
參數:
? ?sockfd:socket函數返回的套接字
? ?addr:要綁定的地址
//sockaddr_in結構, bind時需要強制轉換成為struct sockaddr*類型 struct sockaddr_in {sa_family_t sin_family; /* address family: AF_INET */in_port_t sin_port; /* port in network byte order */struct in_addr sin_addr; /* internet address */ }; /* Internet address. */ struct in_addr {uint32_t s_addr; /* address in network byte order */ }; /**示例:INADDR_ANY的使用, 綁定本機任意地址**/ int main() {int listenfd = socket(AF_INET, SOCK_STREAM, 0);if (listenfd == -1)err_exit("socket error");struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(8001);//綁定本機的任意一個IP地址, 作用同下面兩行語句addr.sin_addr.s_addr = htonl(INADDR_ANY);//inet_aton("127.0.0.1", &addr.sin_addr);//addr.sin_addr.s_addr = inet_addr("127.0.0.1");if (bind(listenfd, (const struct sockaddr *)&addr, sizeof(addr)) == -1)err_exit("bind error");elsecout << "bind success" << endl; }listen函數
int listen(int sockfd, int backlog);? ?listen函數應該用在調用socket和bind函數之后,?并且用在調用accept之前,?用于將一個套接字從一個主動套接字轉變成為被動套接字。
backlog說明:
對于給定的監聽套接口,內核要維護兩個隊列:
? ?1、已由客戶發出并到達服務器,服務器正在等待完成相應的TCP三路握手過程(SYN_RCVD狀態)
? ?2、已完成連接的隊列(ESTABLISHED狀態)
但是兩個隊列長度之和不能超過backlog
backlog推薦使用SOMAXCONN(3.13.0-44-generic中該值為128),?使用等待隊列的最大值;
?
Man-Page中的listen說明:
? ?listen()?marks?the?socket?referred?to?by?sockfd?as?a?passive?socket,?that?is,?as?a?socket?that?
will?be?used?to?accept?incoming?connection?requests?using?accept(2).
? ?The?sockfd?argument?is?a?file?descriptor?that?refers?to?a?socket?of?type??SOCK_STREAM??or?
SOCK_SEQPACKET.
? ?The?backlog?argument?defines?the?maximum?length?to?which?the?queue?of?pending?connections?for?
sockfd?may?grow.??If?a?connection?request?arrives?when?the?queue?is?full,?the??client?may??receive
an??error?with?an?indication?of?ECONNREFUSED?or,?if?the?underlying?protocol?supports?retransmission,?
the?request?may?be?ignored?so?that?a?later?reattempt?at??connection?succeeds.
? If?the?backlog?argument?is?greater?than?the?value?in??/proc/sys/net/core/somaxconn(Ubuntu?14.04?該值為128),??then?it??is??silently?truncated?to?that?value;?the?default?value?in?this?file?is?128.??In?kernels
before?2.4.25,?this?limit?was?a?hard?coded?value,?SOMAXCONN,?with?the?value?128.
?
accept函數
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);從已完成連接隊列返回第一個連接(the?first?connection?request?on?the?queue?of??pending??connections??for?the?listening?
socket,?sockfd,?creates?a?new?connected?socket,?and?returns?a?new?file?descriptor?referring?to?that?socket.?
The?newly?created?socket??is??not??in??the?listening?state),如果已完成連接隊列為空,則阻塞。The?original?
socket?sockfd?is?unaffected?by?this?call.
?
參數:
? ?sockfd:服務器套接字
? ?addr:將返回對等方的套接字地址,?不關心的話,?可以設置為NULL
? ?addrlen:返回對等方的套接字地址長度,?不關心的話可以設置成為NULL,?否則一定要初始化
返回值:
? ?On??success,?these?system?calls?return?a?non-negative?integer?that?is?a?descriptor?for?the?accepted?
socket.??On?error,?-1?is?returned,?and?errno?is?set?appropriately.
?
connect函數
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);建立一個連接至addr所指定的套接字
參數:
? ?sockfd:未連接套接字
? ?addr:要連接的套接字地址
? ?addrlen:第二個參數addr長度
?
示例:echo?server/client實現
//server端代碼 int main() {int listenfd = socket(AF_INET, SOCK_STREAM, 0);if (listenfd == -1)err_exit("socket error");struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(8001);addr.sin_addr.s_addr = htonl(INADDR_ANY);if (bind(listenfd, (const struct sockaddr *)&addr, sizeof(addr)) == -1)err_exit("bind error");if (listen(listenfd, SOMAXCONN) == -1)err_exit("listen error");char buf[512];int readBytes;struct sockaddr_in clientAddr;//謹記: 此處一定要初始化 socklen_t addrLen = sizeof(clientAddr);while (true){int clientfd = accept(listenfd, (struct sockaddr *)&clientAddr, &addrLen);if (clientfd == -1)err_exit("accept error");//打印客戶IP地址與端口號cout << "Client information: " << inet_ntoa(clientAddr.sin_addr)<< ", " << ntohs(clientAddr.sin_port) << endl;memset(buf, 0, sizeof(buf));while ((readBytes = read(clientfd, buf, sizeof(buf))) > 0){cout << buf;if (write(clientfd, buf, readBytes) == -1)err_exit("write socket error");memset(buf, 0, sizeof(buf));}if (readBytes == 0){cerr << "client connect closed..." << endl;close(clientfd);}else if (readBytes == -1)err_exit("read socket error");}close(listenfd); } //client端代碼 int main() {int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd == -1)err_exit("socket error");//填寫服務器端口號與IP地址struct sockaddr_in serverAddr;serverAddr.sin_family = AF_INET;serverAddr.sin_port = htons(8001);serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");if (connect(sockfd, (const struct sockaddr *)&serverAddr, sizeof(serverAddr)) == -1)err_exit("connect error");char buf[512];while (fgets(buf, sizeof(buf), stdin) != NULL){if (write(sockfd, buf, strlen(buf)) == -1)err_exit("write socket error");memset(buf, 0, sizeof(buf));int readBytes = read(sockfd, buf, sizeof(buf));if (readBytes == 0){cerr << "server connect closed... \nexiting..." << endl;break;}else if (readBytes == -1)err_exit("read socket error");cout << buf;memset(buf, 0, sizeof(buf));}close(sockfd); }附-Makefile
.PHONY: clean all CC = g++ CPPFLAGS = -Wall -g -pthread -std=c++11 BIN = server client SOURCES = $(BIN.=.cpp)all: $(BIN) $(BIN): $(SOURCES) clean:-rm -rf $(BIN) bin/ obj/ core總結
以上是生活随笔為你收集整理的Socket编程实践(3) --Socket API的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VIM中常用的替换模式总结
- 下一篇: iOS 动画总结----UIView动画