TCP實戰練習

2021-09-17 18:42:16 字數 3529 閱讀 4727

距離寫這個例項過了太久了,就不寫理論了。此次只實現了單使用者連線,目標是實現多使用者連線並且客戶端之間可以互相通訊,希望以後能補充完全吧。

簡單說一下我在除錯過程中遇到的問題:每次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...