在实现套接字网络通信之前,先来了解一下概念:
socket
socket这个词在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网
络通讯中的一个进程,“IP地址+端口号”就称为socket。
网络字节序
网络通信的时候必须知道端口号,如果发送端是大端字节序,接收端是小端字节序,那么最后看到的端口号就是不正确的端口号,所以,我们必须将端口号在发送端和接收端之间转换成统一的字节序形式,TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节
相关端口
struct sockaddr_in
{
__SOCKADDR_COMMON (sin_); //协议类型
in_port_t sin_port; // Port number
struct in_addr sin_addr; // Internet address
/* Pad to size of `struct sockaddr'. */
unsigned char sin_zero[sizeof (struct sockaddr) -
__SOCKADDR_COMMON_SIZE -
sizeof (in_port_t) -
sizeof (struct in_addr)];
};
socket:申请文件描述符
int socket(int domain, int type, int protocol);
//protocol参数: 与特定的地址家族相关的协议,TCP协议一般为IPPROTO_TCP。也可以写0,那么系统会根据地址格式和套接字类别,自动选择一个适合的协议。
listen:使上面申请到的文件描述符进入监听状态
int listen(int sockfd, int backlog); //backlog连接队列长度
bind:绑定本机的信息,包括,IP地址类型,IP地址,端口号
int bind(int sockfd, cinst struct sockaddr *affr,
socklen_t addrlen);
accept:接受监听套接字,成功返回一个文件描述符(真正用于通信的套接字)
int accept(int sockfd, struct sockaddr *addr,
sochlen_t *addrlen);
下面来完成一个tcp的客户端和用户端的编写
//server.c
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int StartUp(int port,const char* ip)
{
int ListenSock = socket(AF_INET,SOCK_STREAM,0);
if(ListenSock < 0)
{
perror("socket");
exit(1);
}
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = inet_addr(ip);
if(bind(ListenSock,(struct sockaddr*)&local,sizeof(local)) < 0)
{
perror("bind");
exit(2);
}
if(listen(ListenSock,5) < 0)
{
perror("listen");
exit(3);
}
return ListenSock;
}
int main(int argc,const char* argv[])
{
if(argc != 3)
{
printf("input error\n");
return 1;
}
int len;
int listenSock = StartUp(atoi(argv[2]),argv[1]);
struct sockaddr_in client;
while(1)
{
int sock = accept(listenSock,(struct sockaddr*)&client,&len);//获取客户机的信息
if(sock < 0)
{
perror("accept");
continue;
}
printf("get a client,ip is %s,port is %d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
char buf[1024];
while(1)
{
ssize_t s = read(sock,buf,sizeof(buf)-1);//服务器进行读数据
if(s > 0)
{
buf[s] = 0;
printf("client# %s\n",buf);
}
else
{
//数据已经读完了,客户端不发送数据了
printf("client is quit!\n");
}
}
close(sock);
}
return 0;
}
//client.c
#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<arpa/inet.h>
int main(int argc,const char* argv[])
{
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock < 0)
{
perror("socket");
return 1;
}
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[2]));
server.sin_addr.s_addr = inet_addr(argv[1]);
if(connect(sock,(struct sockaddr*)&server,sizeof(server)) < 0)
{
perror("connect");
return 2;
}
char buf[1024];
while(1)
{
printf("send# ");
fflush(stdout);
//从标准输入读数据,读到buf中,然后从buf写到管道
ssize_t s = read(0,buf,sizeof(buf)-1);
if(s < 0)
{
perror("read");
return 3;
}
buf[s-1] = 0;
write(sock,buf,s);
}
close(sock);
return 0;
}