客户端和服务端已经通过socket建立起了TCP连接,接着可以进行数据传输,这里主要用到send和recv,比较简单,他们和系统调用read和write参数类似
#include <sys/socket.h> ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags); ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags);
他们的前三个参数和write,read一样的意思,具体地说是send和write一样,recv和read一样,但是多了一个flags参数,这个标志含义可以baidu,google搜索,一般默认为0
send成功返回的是发送的字节数,出错返回-1,但是成功返回并不代表另一端已经接收数据了,仅仅说明已经发送到网络上了;recv成功返回接收消息字节数,出错返回-1,若没可用消息或者对方已经结束则返回0
于是在前面建立了TCP连接的基础上,添加数据传输的代码,在此过程当中有一些小的操作,比如监听的端口防火墙要开放等等,毕竟这是网络间传输
client端:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #define PORT 9999 #define IPADDR "192.168.1.3" #define MAXSIZE 4096 int main(int argc, char **argv){ int client_sockfd; struct sockaddr_in server_address; char eachline[MAXSIZE]; if ((client_sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){ printf("create socket failed\n"); exit(1); } server_address.sin_family = AF_INET; server_address.sin_port = htons(PORT); if (inet_pton(AF_INET, IPADDR, &server_address.sin_addr) == -1){ printf("inet_pton failed!\n"); exit(1); } if (connect(client_sockfd, (struct sockaddr *)&server_address, sizeof(server_address)) == -1){ printf("connect failed!\n"); exit(1); } fgets(eachline, MAXSIZE, stdin); if (send(client_sockfd, eachline, strlen(eachline), 0) == -1){ printf("send data failed!\n"); exit(1); } printf("send sucessfully!\n"); close(client_sockfd); return 0; }
server端:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #define PORT 9999 #define MAXSIZE 4096 int main(){ int server_sockfd, connect_sockfd; struct sockaddr_in server_address; char buffer[MAXSIZE]; int recv_length; if ((server_sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){ printf("Create socket failed!\n"); exit(1); } memset(&server_address, 0, sizeof(server_address)); server_address.sin_family = AF_INET; server_address.sin_addr.s_addr = htonl(INADDR_ANY); server_address.sin_port = htons(PORT); if (bind(server_sockfd, (struct sockaddr *)&server_address, sizeof(server_address)) == -1){ printf("bind failed!\n"); exit(1); } if (listen(server_sockfd, 10) == -1){ printf("listen socket failed!\n"); exit(1); } if ((connect_sockfd = accept(server_sockfd, (struct sockaddr *)NULL, NULL)) == -1){ printf("connect failed!\n"); exit(1); } printf("Connect sucessfully!\n"); memset(buffer, 0, MAXSIZE); if (recv_length = recv(connect_sockfd, buffer, MAXSIZE, 0) == -1){ printf("recv failed!\n"); exit(1); } buffer[recv_length] = '\0'; printf("Receive data: %s\n", buffer); close(connect_sockfd); close(server_sockfd); return 0; }
分别进行编译,运行:
server端: [lihui@localhost ~]$ cc -o server server.c [lihui@localhost ~]$ ./server 光标 client端: [lihui@localhost ~]$ cc -o client client.c [lihui@localhost ~]$ ./client 光标 server端: [lihui@localhost ~]$ ./server Connect sucessfully! 光标 client端: [lihui@localhost ~]$ ./client helloworld send sucessfully! server端: [lihui@localhost ~]$ ./server Connect sucessfully! Receive data: [lihui@localhost ~]$
结果居然收到的数据为空
1:直接抓包分析
tcpdump port 9999 -w 9.pcap tshark -r 9.pcap -V > 9 在查看了数据包详细信息后发现,第四个包里的确携带了传输的数据 346 [Bytes in flight: 11] 347 Data (11 bytes) 348 349 0000 68 65 6c 6c 6f 77 6f 72 6c 64 0a helloworld. 350 Data: 68656c6c6f776f726c640a 351 [Length: 11] 352 353 Frame 5: 60 bytes on wire (480 bits), 60 bytes captured (480 bits)
可见发送端应该是没有问题的,顺便看下第四个包
1 0.000000 192.168.1.1 -> 192.168.1.3 TCP 66 62579 > distinct [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 WS=4096 2 0.000041 192.168.1.3 -> 192.168.1.1 TCP 66 distinct > 62579 [SYN, ACK] Seq=0 Ack=1 Win=64240 Len=0 MSS=1460 SACK_PERM=1 WS=2048 3 0.000121 192.168.1.1 -> 192.168.1.3 TCP 60 62579 > distinct [ACK] Seq=1 Ack=1 Win=65536 Len=0 4 8.894099 192.168.1.1 -> 192.168.1.3 TCP 65 62579 > distinct [PSH, ACK] Seq=1 Ack=1 Win=65536 Len=11 5 8.894122 192.168.1.1 -> 192.168.1.3 TCP 60 62579 > distinct [FIN, ACK] Seq=12 Ack=1 Win=65536 Len=0 6 8.894147 192.168.1.3 -> 192.168.1.1 TCP 54 distinct > 62579 [ACK] Seq=1 Ack=12 Win=65536 Len=0 7 8.894201 192.168.1.3 -> 192.168.1.1 TCP 54 distinct > 62579 [FIN, ACK] Seq=1 Ack=13 Win=65536 Len=0 8 8.894269 192.168.1.1 -> 192.168.1.3 TCP 60 62579 > distinct [ACK] Seq=13 Ack=2 Win=65536 Len=0
的确是客户端到服务器的包,前面三次握手,后面四次结束
2:gdb直接调试
41 if (recv_length = recv(connect_sockfd, buffer, MAXSIZE, 0) == -1){ (gdb) n 45 buffer[recv_length] = '\0'; (gdb) p recv_length $1 = 0 (gdb) p buffer $2 = "helloworld\n", '\000' <repeats 4084 times>
这玩意就神奇了,居然返回是0,说实话我还又把recv研究了一遍,以及第四个参数的含义等等,依旧没找到原因
3:正当灰头土脸的时候,细看了一眼折磨我的recv,以及它的四周,就感觉这括号对不对呀?此刻心里顿时那几千头啥:
if (recv_length = recv(connect_sockfd, buffer, MAXSIZE, 0) == -1)
recv返回字节数,== -1为假,于是0赋给recv_length,所以返回字节数才是0,应该改成
if ((recv_length = recv(connect_sockfd, buffer, MAXSIZE, 0)) == -1){
重新编译,执行一把,这才对嘛~!
server端: [lihui@localhost ~]$ cc -o server server.c [lihui@localhost ~]$ ./server 光标 client端: [lihui@localhost ~]$ cc -o client client.c [lihui@localhost ~]$ ./client 光标 server端: [lihui@localhost ~]$ ./server Connect sucessfully! 光标 client端: [lihui@localhost ~]$ ./client helloworld send sucessfully! server端: [lihui@localhost ~]$ ./server Connect sucessfully! Receive data: helloworld [lihui@localhost ~]$