http://kezeodsnx.pixnet.net/blog/post/27462696-socket-programming-%E7%AD%86%E8%A8%98
http://beej-zhtw.netdpi.net/05-system-call-or-bust/5-2-socket--get-file-descriptor
http://www.tenouk.com/cnlinuxsockettutorials.html
TCP&UDP 基本區別
TCP
優點:
可靠性、順序性
缺點:
建立連線 速度比較慢。
tcp 可靠性確保=>
UDP
優點:
傳輸速度快
缺點:
不可靠 可能資料lost 看網卡buffer
TCP
優點:
可靠性、順序性
缺點:
建立連線 速度比較慢。
tcp 可靠性確保=>
Acknowledge
Retransmission
Sequence Number
Checksum
https://blog.longwin.com.tw/2006/12/tcp_ip_data_sync_2006/
https://stackoverflow.com/questions/1157644/are-sockets-reliable
Retransmission
Sequence Number
Checksum
https://blog.longwin.com.tw/2006/12/tcp_ip_data_sync_2006/
https://stackoverflow.com/questions/1157644/are-sockets-reliable
UDP
優點:
傳輸速度快
缺點:
不可靠 可能資料lost 看網卡buffer
TCP:
UDP
基本指令
- socket:
int socket(int domain, int type, int protocol);
domain | 所以這裡只會用到 IPv4 的 PF_INET 及 IPv6 的 PF_INET6。 |
type | 可靠 TCP socket 的 SOCK_STREAM(send(), recv()) 不可靠快速 UDP socket 之 SOCK_DGRAM(sendto(), recvfrom()) [另一個有趣的 socket type 是 SOCK_RAW,這個可以用來手動建構封包表頭] |
protocol | protocol 參數指定在特定的 socket type 要用的 protocol(通訊協定),正如我所說的,比如:SOCK_STREAM 使用 TCP。在使用 SOCK_STREAM 或 SOCK_DGRAM 時,你可以直接將 protocol 設定為zero,這樣它會自動使用適合的 protocol,要不然你可以用 getprotobyname() 查詢適合的協定編號(protocol number)。 |
struct addrinfo
{ int ai_flags; int ai_family; int ai_socktype; int ai_protocol; socklen_t ai_addrlen; struct sockaddr *ai_addr; char *ai_canonname; struct addrinfo *ai_next; };
参数
|
取值
|
值
|
说明
|
ai_family
|
AF_INET
|
2
|
IPv4
|
AF_INET6
|
23
|
IPv6
| |
AF_UNSPEC
|
0
|
协议无关
| |
ai_protocol
|
IPPROTO_IP
|
0
|
IP协议
|
IPPROTO_IPV4
|
4
|
IPv4
| |
IPPROTO_IPV6
|
41
|
IPv6
| |
IPPROTO_UDP
|
17
|
UDP
| |
IPPROTO_TCP
|
6
|
TCP
| |
ai_socktype
|
SOCK_STREAM
|
1
|
流
|
SOCK_DGRAM
|
2
| ||
ai_flags
|
AI_PASSIVE
|
1
|
被动的,用于bind,通常用于server socket
|
AI_CANONNAME
|
2
| 用于返回主机的规范名称 | |
AI_NUMERICHOST
|
4
|
地址为数字串
|
程式碼:
getaddrinfo(NULL, "3490", &hints, &res);
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
source path=>google drive/Book CS/Socket/SocketGetaddrinfo
https://drive.google.com/file/d/1WB1L05am7DGPxLLxHhYW-Nwptg60p4zI/view?usp=sharing
- Bind
int bind(int socketfd, struct sockaddr *my_addr, socklen_t addrlen);
struct sockaddr是通用的套接字地址,而struct sockaddr_in则是internet环境下套接字的地址形式,二者长度一样,都是16个字节。
二者是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr。一般情况下,需要把sockaddr_in结构强制转换成sockaddr结构再传入系统调用函数中。
return:
On success, zero is returned. On error, -1 is returned
程式碼:
bind(sockfd, res->ai_addr, res->ai_addrlen);
p.s. 不要bind same port
- Listen
int listen(int socketfd, int backlog);
參數 backlog 代表在 kernel 開始拒絕新連線以前,你可以有多少的連線在等待。所以當新的連線進入時,你應該盡快的用 accept() 來處理,讓 backlog 不會滿出來。
return:
On success, zero is returned. On error, -1 is returned
程式碼:
listen(sockfd, 10);
- Accept
int accept(int socketfd, struct sockaddr *addr, socklen_t *addrlen);
原本用來 listen 的 socket 仍然還是會留著,當有新連線進來時,一樣是用 accept() call 來接受新的連線。
addr | 這裡會填入連線到server這裡的 client 位址。 |
addrlen | 這裡會填入 addr 參數中傳回的資料結構大小。 |
程式碼:
struct sockaddr_storage their_addr;
int addr_size=sizeof(struct sockaddr_in);
int new_fd = accept(sockfd, (struct sockaddr *)&their_addr, (socklen_t*)&addr_size);
return:
On success, these system calls return a file descriptor for the accepted socket. On error, -1 is returned,
- Connect
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
填入 serv_addr , 要連接的server
return:
On success, zero is returned. On error, -1 is returned
- recv
ssize_t recv(int s, void *buf, size_t len, int flags);ssize_t recvfrom(int s, void *buf, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen);
TCP SOCK_STREAM socket 使用 recv() 、UDP SOCK_DGRAM socket 使用 recvfrom()。
recv(sockfd, buf, len, flags);
is equivalent to
recvfrom(sockfd, buf, len, flags, NULL, NULL);
flags is zero 表示 不包含任何flag
p.s. recv vs read
- send
ssize_t send(int s, const void *buf, size_t len, int flags);ssize_t sendto(int s, const void *buf, size_t len,
int flags, const struct sockaddr *to,
socklen_t tolen);
send() 用在需連線的 TCP SOCK_STREAM socket,而 sendto() 用在免連線的 UDP SOCK_DGRAM socket。
flags is zero 表示 不包含任何flag
p.s. send vs write
flag可參考:
http://www.mit.edu/afs.new/athena/system/i386_deb50/os-ubuntu-9.04/usr/include/bits/socket.h
- recv vs read
With a zero flags argument, recv() is generally equivalent to read().只有在datagram 時 ,收到長度為0的pending,recv 會drop,read會保留.
- send vs write
write():On success, the number of bytes written are returned (zero indicates nothing was written). On error, -1 is returned, and errno is set appropriately. If count is zero and the file descriptor refers to a regular file, 0 will be returned without causing any other effect. For a special file, the results are not portable.
send():
The calls return the number of characters sent, or -1 if an error occurred.
因為send 可能長度太長失敗
If the message is too long to pass atomically through the underlying protocol,
the error EMSGSIZE is returned, and the message is not transmitted.
https://stackoverflow.com/questions/9048959/write-and-send-solving-errors-difference
*另外注意
"recv byte & 次數" 與 "send &次數" 不一定對等舉例,
send 3000byte 一次, recv buffer 調5000byte (也並非一次一定收到3000byte)
send 100byte 3次 , recv 可能一次收到300byte.
沒有留言:
張貼留言