距離寫這個例項過了太久了,就不寫理論了。此次只實現了單使用者連線,目標是實現多使用者連線並且客戶端之間可以互相通訊,希望以後能補充完全吧。
簡單說一下我在除錯過程中遇到的問題:每次kill掉該伺服器程序並重新啟動的時候,都會出現bind錯誤:error:98,address already in use。然而再kill掉該程序,再次重新啟動的時候,就bind成功了。原因是tcp再關閉連線時,為了保證雙向完全關閉,沒有將埠釋放,可以通過setsockopt設定埠復用(so_reuseaddr),在最終版本要將設定取消,違背了tcp的安全性。
server_tcp.c
#include #include #include #include #include #include #include #include #define server_port 65535
#define listen_backlog 5
#define socket_buf_rdwr 512
int main(void)
; int on = 1;
socket_ser_fd = socket(af_inet, sock_stream, 0);
if (socket_ser_fd < 0)
/* 設定埠復用,on=0關閉,最終版本需要關閉 */
setsockopt(socket_ser_fd, sol_socket, so_reuseaddr, &on, sizeof(on));
addr_server.sin_family = af_inet;
addr_server.sin_port = htons(server_port);
/*addr_server.sin_addr.s_addr = inet_addr(server_ip);*/
addr_server.sin_addr.s_addr = inaddr_any;
memset(addr_server.sin_zero, 0, 8);
ret = bind(socket_ser_fd, (struct sockaddr*)&addr_server,
sizeof(struct sockaddr));
if (ret < 0)
ret = listen(socket_ser_fd, listen_backlog);
if (ret < 0)
addr_len = sizeof(struct sockaddr);
socket_cli_fd = accept(socket_ser_fd, (struct sockaddr *)&addr_client,
(socklen_t *)&addr_len);
if (socket_cli_fd < 0)
while (1)
printf("server get %d data:%s\n", size, buf);
memset(buf, 0, socket_buf_rdwr);
sprintf(buf, "server get %d data\n", size);
size = write(socket_cli_fd, buf, strlen(buf));
if (size < 0)
printf("server set %d data:%s\n", size, buf);
} close(socket_cli_fd);
close(socket_ser_fd);
return 0;
}
client_tcp.c
#include #include #include #include #include #include #include #define server_port 65535
#define socket_buf_rdwr 512
int main(int ar**, char* argc)
; if (ar** < 2)
client_fd = socket(af_inet, sock_stream, 0);
if (client_fd < 0)
server_addr.sin_family = af_inet;
server_addr.sin_port = htons(server_port);
server_addr.sin_addr.s_addr = inet_addr(argc[1]);
memset(server_addr.sin_zero, 0, 8);
addr_len = sizeof(struct sockaddr_in);
ret = connect(client_fd, (struct sockaddr *)&server_addr,
addr_len);
if (ret < 0)
while (1)
printf("client set %d data:%s\n", size, buf);
size = read(client_fd, buf, socket_buf_rdwr);
if (size < 0)
printf("client get %d data:%s\n", size, buf);
} close(client_fd);
return 0;
}
makefile
#將此目錄下的c檔案獲取
source = $(wildcard *_tcp.c)
#將source中的名字字尾替換
targets = $(patsubst %_tcp.c, %, $(source))
objs =
#有兩種理由需要使用phony 目標:避免和同名檔案衝突,改善效能
#此處用於改善效能,可以告知all目標並不是實際產生的檔案
.phony:all
#基本變數賦值,這裡代表選擇編譯器
cc = gcc
#cflags 表示用於 c 編譯器的選項
#-wall 選項可以列印出編譯時所有的錯誤或者警告資訊
#-g 選項是指可以用gdb除錯
cflags = -wall -g
all:$(targets)
# $^ 代表所有的依賴物件
# $@ 代表目標
# $< 代表第乙個依賴物件
# %:%_tcp.c
# 模式變數表示與目標相同的_tcp.c檔案
$(targets):%:%_tcp.c $(objs)
$(cc) $^ $(cflags) -o $@
# @echo "begin"
# @echo $^
# @echo $<
# @echo $(source)
# @echo $(targets)
# @echo "end"
clean:
rm -rf $(targets) $(objs)
執行環境:ubnutu 16.04
目標 :server client
依賴 :server_tcp.c client_tcp.c
react hooks 實戰練習
在class中,我們是通過建構函式中,設定state的 this.state 在函式中,沒有this,所以之前的this都不能分配和讀取了,然後在hook中用到了usestate import react,from react 先引入usestate const customeraccess pro...
linux實戰練習
1 鏈結到nginx部署的伺服器 2 檔案查詢,find name nginx,找到nginx的目錄 3 進入到nginx cd 的目錄下,然後檢視檔案,找到logs,進入logs目錄下,然後 pwd 檢視當前目錄 4 然後tail f error.log就可以檢視到實時的錯誤日誌。5 截圖給開發。...
golang實戰小練習
統計 某路徑下 某些指定檔案中 指定字串出現的次數 用到的外部庫 allfiletextnum 統計 某路徑下 某些指定檔案中 指定字串出現的次數 dir string 指定查詢路徑 sixs string 指定查詢的字尾 text string 指定統計字串 return 指定字串出現的次數 in...