客户端和服务端已经通过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 ~]$
