1. TCP客户端程序实现步骤
-
创建套接字,准备网路连接
-
请求连接
-
收发数据完成数据交换
-
断开连接
与服务端相比的区别在于请求连接
,它是创建客户端套接
字后向服务端发起的连接请求。
2. 客户端的实现细节
-
connect
函数原型
#include <sys/socket.h> int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数说明:
sockfd:客户端套接字的文件描述符
addr:保存目标服务器的地址信息的结构体变量
addrlen:地址长度单位为字节
客户端调用connect函数后,发生以下情况之一才会返回(完成函数调用)
-
服务器接收连接请求 (接收连接请求并不意味着服务端调用了accept函数创建了新的socket与客户端socket 建立了连接,而实际是指服务端把连接请求的信息记录到等待队列中,所以connect函数返回后并不立即进行数据交换)
-
发生断网等异常情况而中断连接请求
-
-
客户端套接字
在下一节的服务端程序中我们会为套接字分配ip和端口,但是,客户端程序中并未出现套接字地址端口数据分配,而是直接创建了套接字之后直接connect函数进行调用,难道客户端程序不需要进行ip和端口的分配?当然不是,网络数据交换必须分配IP和端口。既然如此,那客户端程序套接字是何时、何地、如何进行地址端口分配?
- 何时:调用connect函数时
- 何地:操作系统,更准确的说是在内核中
- 如何:IP用计算机(主机)的IP,端口随机
客户端的地址以及端口在调用connect函数时
自动分配
,无需调用标记的bind函数进行分配
3. 实例
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(int argc,char* argv[])
{
int sock = 0;
struct sockaddr_in addr = {0};
char* tosend="hello tcp client.";
int len = 0;
char buf[128] = {0};
int r = 0;
if(argc!=3)
{
printf("Usage:%s <IP> <Port>\n" , argv[0]);
}
sock = socket(PF_INET, SOCK_STREAM, 0);//创建准备用于连接服务端的套结字,此时创建的是TCP套接字
if( sock == -1 )
{
printf("socket error\n");
return -1;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(argv[1]);
addr.sin_port = htons(atoi(argv[2]));
if( connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1 )//用向服务端发起连接请求
{
printf("connect error\n");
return -1;
}
printf("connect success\n");
len = send(sock, tosend, strlen(tosend), 0);
printf("send bytes = %d\n", len);
len = 0;
do
{
int i = 0;
r = recv(sock, buf, sizeof(buf), 0);
if( r > 0 )
{
len += r;
}
for(i=0; i<r; i++)
{
printf("%c", buf[i]);
}
} while ( r > 0 );
printf("\n");
printf("recv bytes = %d\n", len);
close(sock);
return 0;
}
/*
linux@ubuntu:~/demos/demos/socket_client$ ./a.out 192.168.2.26 8089
connect success
send bytes = hello tcp client.
send bytes = 17
recv bytes = qqqqq
recv bytes = 5
*/
可直接使用TCP模拟工具模拟TCP Server端.