对于TCP的写作流程,分为对客户端代码的编写和服务端代码的编写
这两端的流程都是差不多的
对于TCP客户端的代码编写
第一步、首先需要创建属于客户端的TCP的套接字
PF_INET表示使用的是IPV4的网络,SOCK_STREAM表示使用的是TCP的流式套接字
int sock_fd = socket(PF_INET,SOCK_STREAM,0);
if(sock_fd==-1)
{
perror("sock_fd error");
return -1;
}
这里还需要判断套接字是否创建成功,创建失败返回-1
第二步、连接对应的服务器端,初始化对应的服务器的IP和端口
首先声明服务端结构
再设置对应的IP号和端口号
在连接到对应的服务端
这里的AF_INET和PF_INET是一样的,只是在套接字的使用时使用PF_INET,在结构体使用时使用AF_INET。
struct sockaddr_in serverAddr;
serverAddr.sin_family=AF_INET;
serverAddr.sin_port=2000;
serverAddr.sin_addr.s_addr="192.168.1.2";
int connect_ret=connect(sock_fd,(struct sockaddr_in *)&serverAddr,sizeof(serverAddr));
if(connect_ret==-1)
{
perror("connect_ret error");
return -1;
}
这里和上面一致需要看是否连接成功;
同时对端口和IP的设置可以上面这样设置,但只能在同一个主机或者同一个虚拟机中运行,不能访问到其他的主机,若需要访问到其他的主机则需要进行如下的设置:
serverAddr.sin_port=htons(12341);
serverAddr.sin_addr.s_addr=inet_addr("47.108.235.65");
这里的htons是主机转网络,将主机端口号转成网络端口号
这里的inet_addr是将主机IP转换成网络IP,这样就能实现对其他主机的连接了
你可能会问有没有网络转主机的呢?
当然有,ntohs()就是将网络端口号转换成主机端口号
同样的IP也有inet_network()就是将网络地址转换成主机地址,当然还有其他几个,这里没有用到就不赘述了
那么接下来就可以进行客户端到网络端的通信了
第三步、发送数据到服务端
首先定义一个buf存贮发送的数据,再通过send()函数发送到服务端
char buf[1024]={0};
while(1)
{
memset(buf,0,sizeof(buf));
printf("发送:\n");
fgets(buf,sizeof(buf),stdin);
send(sock_fd,buf,strlen(buf),0);
printf("发送的数据:\n",buf);
}
第四步、就关闭套接字
close(sock_fd);
这样就实现了对TCP客户端代码的实现
代码:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
int main(void)
{
/*创建套接字*/
int sock_fd=socket(PF_INET,SOCK_STREAM,0);
if(sock_fd==-1)
{
printf("sock_fd error\n");
return -1;
}
/*服务器的IP号和端口号*/
struct sockaddr_in serverAddr;
serverAddr.sin_family=AF_INET;
serverAddr.sin_port=htons(12341);
serverAddr.sin_addr.s_addr=inet_addr("47.108.235.65");
int connet_s=connect(sock_fd,(struct sockaddr *)&serverAddr,sizeof(struct sockaddr_in));
if(connet_s==-1)
{
printf("connet_s error\n");
return -1;
}
/*发送数据*/
char buf[1024]={0};
while(1)
{
memset(buf,0,sizeof(buf));
printf("发送:\n");
fgets(buf,1024,stdin);
send(sock_fd,buf,strlen(buf),0);
printf("发送的数据:%s\n",buf);
}
/*关闭套接字*/
close(sock_fd);
}
对于TCP服务端的代码编写
服务端的思路与客户端类似
第一步、首先需要创建属于服务端的TCP的套接字
int sock_fd = socket(PF_INET,SOCK_STREAM,0);
if(sock_fd==-1)
{
perror("sock_fd error");
return -1;
}
第二步、这就需要绑定自己(就是服务端)的IP和端口号,这里与客户端的区别就是多了一个绑定
struct sockaddr_in OwnAddr;
OwnAddr.sin_family=AF_INET;
OwnAddr.sin_port=htons(12341);
OwnAddr.sin_addr.s_addr=inet_addr("172.20.189.35");
bind(sock_fd,(struct sockaddr *)&OwnAddr,sizeof(OwnAddr));
第三步,设置监听,因为需要监听客户端是否发起连接或者是否发送数据
listen(sock_fd,5);
第四步、需要再次声明客户端的结构体,以及结构体大小,需要接收到客户端的IP和端口号以及数据
struct sockaddr_in ClientAddr;
int length=sizeof(struct sockaddr_in);
第五步、接收客户端的连接请求,并检查是否成功。
如果成功,它会返回一个新的套接字文件描述符;如果失败,它会输出一个错误消息并返回-1
然后在将连接的客户端的IP和端口号打印出来
int clientNew_fd=accept(sock_fd,(struct sockaddr *)&ClientAddr,&length);
if(clientNew_fd==-1)
{
printf("clientNew_fd error\n");
return -1;
}
printf("the costmer IP:%s ,the costmer port:%d\n",inet_ntoa(ClientAddr.sin_addr),ntohs(ClientAddr.sin_port));
第六步、就需要接收客户端发送的数据
需要定义buf接收数据 recv接收数据
char buf[1024]={0};
while(1)
{
sleep(1);
memset(buf,0,sizeof(buf));
recv(clientNew_fd,buf,sizeof(buf),0);
printf("the data:%s\n",buf);
}
第七步、关闭服务端套接字
close(sock_fd);
close(clientNew_fd);
这样服务端的代码就写完了
代码:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
int main(void)
{
/*创建套接字*/
int sock_fd=socket(PF_INET,SOCK_STREAM,0);
if(sock_fd==-1)
{
printf("sock_fd error\n");
return -1;
}
/*绑定自己的IP号和端口号*/
struct sockaddr_in OwnAddr;
OwnAddr.sin_family=AF_INET;
OwnAddr.sin_port=htons(12341);//htons--->将主机端口号变成网络端口号 host to network short
OwnAddr.sin_addr. s_addr=inet_addr("172.20.189.35");//inet_addr将主机IP转换为网络IP
bind(sock_fd,(struct sockaddr *)&OwnAddr,sizeof(OwnAddr));
/*设置监听*/
listen(sock_fd,5);
/*等待连接*/
struct sockaddr_in ClientAddr;
int length=sizeof(struct sockaddr_in);
int clientNew_fd=accept(sock_fd,(struct sockaddr *)&ClientAddr,&length);
if(clientNew_fd==-1)
{
printf("clientNew_fd error\n");
return -1;
}
printf("the costmer IP:%s ,the costmer port:%d\n",inet_ntoa(ClientAddr.sin_addr),ntohs(ClientAddr.sin_port));
/*接收数据*/
char buf[1024]={0};
while(1)
{
sleep(1);
memset(buf,0,sizeof(buf));
recv(clientNew_fd,buf,sizeof(buf),0);
printf("the data:%s\n",buf);
}
/*关闭套接字*/
close(sock_fd);
close(clientNew_fd);
}
TCP(IP地址)(补)
如果服务器和客户端是在同一个主机上,如:使用Ubuntu系统中分别跑服务端和客户端,那么其IP地址必须一致,否则失败。
如果服务器和客户端是不在同一个主机上,情况一:一个主机与另一个主机,看那个主机作为服务器那个主机作为客户端,作为服务器的主机就设置自己的本地IP,作为客户端的主机就设置服务器的IP;情况二:一个主机和云服务器,将云服务器的IP地址设置为云服务器私网IP,客户端的地址设置为云服务器的公网IP。