./server [ip] [port]
1.int port = atoi(argv[2]);
2.int listen_sock = start(argv[1],port); //usefull sock
int start(char *ip,short port);
{
int sock_fd = socket(AF_INET,SOCK_STREAM,0);
【int socket(int domain
//AF_INET
,int type
//SOCK_STREAM
,int protocol
//0
);】
虽然已经创建出一个文件描述符,但是还应该把这个文件描述符绑定到特定的IP地址和端口上,所以要先将IP地址和端口填充到本地。
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(port);//port : host -> net
【uint16_t htons(uint16_t hostshort)】
inet_aton(argv[1],&local.sin_addr);//ip : xxx.xxx.xxx.xxx -> int
【int inet_aton(const char *cp,struct in_addr *inp)
//把网络地址IP(主机字节序列)转化成二进制格式(网络字节序列)并存储在inp中,也就是local.sin_addr
】
IP地址与端口已经填充到本地的变量中,现在要将这个变量绑定到之前创建出来的文件描述符中
bind(scok_fd,(struct sock_addr)&local,sizeof(local));
【int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen)】
但是,当前的sock_fd还不能使用,还要监听。
listen(sock_fd,5);
【int listen(int sockfd,int backlog)】
return sock_fd;
}
3.第2步创建出一个监听套接字。
创建出一个监听套接字之后,要不断的accept新的链接来提供服务
struct sockaddr_in remote;
memset(&remote,'\0',sizeof(remote));
socklen_t len = sizeof(remote);
int new_sock = accept(listen_sock,(struct sockaddr*)&remote,&len);
【int accept(int sockfd,struct sockaddr *addr
//拿到对方的socket
,socklen_t *addrlen)
//既是输入型参数又是输出型参数(输入的时候告诉函数缓冲区有多大,输出的时候表明拿到的数据有多大)
】
4.while(1)
{
char buf[1024];
memset(buf,'\0',sizeof(buf));
ssize_t sz = read(new_sock,buf,sizeof(buf)-1);
sz > 0 说明读数据成功,write(new_sock,buf,strlen(buf))//回显
sz == 0说明服务器端链接断开,close(new_sock);
sz < 0说明读到文件结尾
}
./client [ip] [remote_port]
1.int port = atoi(argv[2]);
int conn_fd = socket(AF_INET,SOCK_STREAM,0);
//创建一个远端socket
2.struct sockaddr_in remote;
remote.sin_family = AF_INET;
remote.sin_port = htons(port);
inet_aton(argv[1],&remote.sin_addr);
已经创建出来,也已经把IP地址和端口填充进去,但不需要绑定
但这时要用到connect函数,
connect(conn_fd,(struct sockaddr*)&remote,sizeof(remote));
//如果失败要关闭conn_fd
【int connect(int sockfd,const struct sockaddr* addr,socklen_t addrlen)】
3.char buf[1024];
while(1)
{
memset(buf,'\0',sizeof(buf));
gets(buf);
write(conn_fd,buf,strlen(buf));
read(conn_fd,buf,sizeof(buf));
}