stdin,stdout,stderr算法
名稱 | 全稱 | 含義 |
---|---|---|
stdin | standard input | 標準輸入流 |
stdout | standard out | 標準輸出流 |
stderr | standard error | 標準錯誤輸出 |
咱們來看下面幾個函數bash
#include <stdio.h>
#define BUF_SIZE 5
int main(int argc, char *argv[])
{
char message[BUF_SIZE];
fputs("請向輸入流一個字符串:", stdout); //printf
fgets(message, BUF_SIZE, stdin); //scanf
fputs(message,stderr); //output: message
}
複製代碼
上面咱們使用到了stdout、 stdin, 而且最後還寫入到 stderr流, 輸出到了控制檯.網絡
stdout和stderr都能輸出到控制檯, 除了語義上區別外, stderr是沒有緩衝的,他當即輸出,而stdout默認是行緩衝,也就是它遇到‘\n’,才向外輸出內容,若是你想stdout也實時輸出內容,那就在輸出語句後加上fflush(stdout),這樣就能達到實時輸出的效果socket
fputs、fgets指定到流的操做(文件流), 對應的直接輸入輸出還有 puts、gets,這裏再也不推薦使用puts、gets了, 他們之間也有區別函數
gets()丟棄輸入中的換行符,可是puts()在輸出中添加換行符。另外一方面,fgets()保留輸入中的換行符,fputs()不在輸出中添加換行符,所以,puts()應與gets()配對使用,fputs()應與fgets()配對使用。ui
echo_server.c編碼
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define BUF_SIZE 5
int main(int argc, char *argv[])
{
char message[BUF_SIZE];
int str_len, i;
struct sockaddr_in serv_addr, clnt_addr;
int serv_sock = socket(PF_INET, SOCK_STREAM, 0);
if (serv_sock == -1)
{
printf("socket() error");
exit(1);
}
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(9600);
if (bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
{
printf("bind() error");
exit(1);
}
if (listen(serv_sock, 5) == 1)
{
printf("listen() error");
exit(1);
}
int clnt_addr_sz = sizeof(clnt_addr);
for (i = 0; i < 5; i++)
{
int clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_addr, &clnt_addr_sz);
if (clnt_sock == -1)
{
printf("accept() error");
exit(1);
}
while (str_len = read(clnt_sock, message, BUF_SIZE) > 0)
{
write(clnt_sock, message, str_len);
}
close(clnt_sock);
}
close(serv_sock);
return 0;
}
複製代碼
echo_client.cspa
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define BUF_SIZE 5
int main(int argc, char *argv[])
{
char message[BUF_SIZE];
int str_len, i;
struct sockaddr_in serv_addr, clnt_addr;
int serv_sock = socket(PF_INET, SOCK_STREAM, 0);
if (serv_sock == -1)
{
printf("socket() error");
exit(1);
}
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_port = htons(9600);
if (connect(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
{
printf("connect() error");
exit(1);
}
while (1)
{
fputs("請輸入您的信息,按Q鍵退出\n", stdout);
fgets(message, 1024, stdin);
//由於fgets會保留輸入中換行符,故判斷加\n
if (!strcmp(message, "q\n") || !strcmp(message, "Q\n"))
{
break;
}
write(serv_sock, message, sizeof(message));
read(serv_sock, message, BUF_SIZE - 1);
printf("Message from server: %s\n", message);
}
close(serv_sock);
return 0;
}
複製代碼
上面代碼簡單完成了 echo 的操做(咱們輸入什麼,服務端返回什麼)3d
咱們發現當數據超過5個字符時候(\n也默認爲一個字符), 將會截斷髮送, 咱們能夠使用下面方式。指針
str_len = write(serv_sock, message, strlen(message));
recv_len = 0;
while (recv_len < str_len)
{
recv_cnt = read(serv_sock, &message[recv_len], BUF_SIZE - 1);
if (recv_cnt == -1)
{
printf("read() error");
exit(1);
}
recv_len += recv_cnt;
}
複製代碼
上面將是循環接收數據, 直到接收完畢退出循環體
#include <stdio.h>
#include <netdb.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
struct hostent *host;
host = gethostbyname("www.xueba100.com");
printf("h_name=%s\n", host->h_name);
printf("h_addrtype=%d\n", host->h_addrtype);
int i;
for (i = 0; host->h_addr_list[i]; i++)
{
//將IP指針轉換爲 in_addr 結構體, 再調用inet_ntoa轉換爲字符串形式
printf("Ip addr: %s\n", inet_ntoa(*(struct in_addr *)host->h_addr_list[i]));
}
}
複製代碼
這裏舉例說明 設置 SO_REUSEADDR 選項
當咱們主動關閉服務端時候, 將會產生TIME_OUT, 這樣會致使端口地址沒法重用,規範中規定等待 2MSL 時間才能夠使用。 咱們能夠使用 setsockopt 設置地址重用。
socklen_t option;
int optlen = sizeof(option);
option = 1;
setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, (void *)&option, optlen);
複製代碼
與之對應的 getscokopt 函數, 獲取選項
只有收到前一數據的 ACK 消息時, Nagle 算法才發送下一數據。
TCP 套接字默認使用的 Nagle 算法交換數據, 所以最大限度地進行緩衝, 直到收到 ACK。
若是不使用 Nagle 無需等待 ACK 的前提下連續傳輸, 大大提升傳輸速度.
使用 Nagle 交互圖
把圖畫殘了。。。
當咱們傳輸大文件, 注重傳輸速度時候能夠禁用 Nagle 算法, 若是考慮到傳輸內容很小, 頭部信息就有可能幾十個字節, 能夠使用 Nagle 算法, 減小網絡傳輸次數。
禁用 Nagle 算法
socklen_t option;
int optlen = sizeof(option);
option = 1;
setsockopt(serv_sock, IPPROTO_TCP, TCP_NODELAY, (void *)&option, optlen);
複製代碼