一:网络编程概述
引入网络编程:进行多机通讯
网络编程:地址+数据
- 地址:以IP地址+端口号进行区分,IP地址可以知道主机位置,但是不知道具体运行的是哪个服务器,需要加上端口号进行区别
- 数据即协议,也就是通过各种数据格式进行确认
- 服务器一般都是通过知名端口号来识别的。例如,对于每个TCP/IP实现来说,FTP服务器的TCP端口号都是21,每个Telnet服务器的TCP端口号都是23,每个TFTP(简单文件传送协议)服务器的UDP端口号都是69
主要协议有TCP/UDP
- TCP面向连接,如打电话前需要拨号进行连接,而UDP无需连接,是面向报文的,即发送数据前不用建立连接
- TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付,只能用于不需要保证数据精确度的地方
- TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的 UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
- 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
- TCP首部开销20字节;UDP的首部开销小,只有8个字节
- TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
二:字节序
字节序是指多字节数据在计算机内存中存储或网络传输的各字节的存储数据
有小端字节序与大端字节序
小端字节序(little endian):将低序字节存放在起始位置
大端字节序(big endian):将高序字节存放在起始位置
三:socket编程
- 创建套接字
- 为套接字添加信息(IP地址和端口号)
- 监听网络连接
- 监听到有客户端介入,接受一个连接
- 数据交互
- 关闭套接字,断开连接
1.连接协议
int socket(int domain, int type, int protocol);
参数:
domain:协议族,AF_INET
type:通信类型,tcp协议为SOCK_STREAM
protocal:具体的协议,一般为0,默认协议
返回值: 文件描述符
2.准备地址
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
参数:
sockfd:socket返回的文件描述符
addr:地址结构指针,存放ip地址和端口编号
addrlen 地址结构的长度
返回值 0
说明:地址结构体为:
struct sockaddr
{
sa_family_t sa_family; //地址协议族
char sa_data[14]; //地址 端口编号
}
这么写是为了适用于各个协议,却不能将32位的二进制IP地址和短整
型数据的端口编号存储到一个字符数组里,所以使用另一个结构体来
代替它:
struct sockaddr_in
{
sa_family_t sin_family; //地址协议族
in_port_t sin_port //端口编号,2byte
struct in_addr sin_addr; //IP地址结构体
unsigned char sin_zero[8]; //填充,没有实际意义
};
注:该结构体在/usr/include/netinet/in.h里已被定义,
头文件为<netinet/in.h> ;
3.监听
int listen(int sockfd, int backlog);
参数 sockfd 文件描述符
backlog 等待队列元素个数
当客户端向服务器发起连接时,服务器的监听描述符在端口上收到了
客户端的连 接请求后,并不是立刻建立连接,而是先将请求放在等
待的队列中,然后从队列中按照先后顺序取出请求,建立连接。
返回值 0代表成功
4.连接
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数:sockfd:监听用文件描述符
Addr:入参,是连接来的客户端的地址结构
addrlen 地址结构的长度指针
返回值:文件描述符 用于进行通信的描述符
5.数据收发
read/write
或send/recv
客户端用于连接
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
参数:sockfd 通信用描述符
addr 目标服务器的地址结构指针
addrlen 地址结构的长度
返回值:成功与否 0/非0
serve.c
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
int main(int argc,char **argv)
{
int s_fd;
int c_fd;
int mark = 0;
char readBuf[128];
char msg[128] = {0};
// char *msg = "I get your msg\n";
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
memset(&s_addr,0,sizeof(struct sockaddr_in));
memset(&c_addr,0,sizeof(struct sockaddr_in));
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1],&s_addr.sin_addr);
//1.socket
s_fd = socket(AF_INET,SOCK_STREAM,0);
if(s_fd == -1){
perror("socket");
exit(0);
}
//2.bind
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//3.listen
listen(s_fd,10);
//4.accept
int clen = sizeof(struct sockaddr_in);
while(1){
c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);
if(c_fd == -1){
perror("accept");
}
mark++;
printf("connect ip:%s\n",inet_ntoa(c_addr.sin_addr));
if(fork() == 0){
if(fork() == 0){
while(1){
//6.write
memset(msg,0,sizeof(msg));
sprintf(msg,"welcome to %d clinet",mark);
write(c_fd,msg,strlen(msg));
sleep(3);
}
}
//5.read
while(1){
memset(readBuf,0,sizeof(readBuf));
int n_read = read(c_fd,readBuf,128);
if(n_read == -1){
perror("read");
exit(-1);
}else{
printf("read meassage:%d,%s\n",n_read,readBuf);
}
break;
}
}
}
return 0;
}
client.c
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
int main(int argc,char **argv)
{
int c_fd;
int n_read;
char readBuf[128];
// char *msg = "msg from client\n";
char msg[128] = {0};
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr_in));
c_addr.sin_family = AF_INET;
c_addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1],&c_addr.sin_addr);
//1.socket
c_fd = socket(AF_INET,SOCK_STREAM,0);
if(c_fd == -1){
perror("socket");
exit(0);
}
//2.connect
if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr))){
printf("connect success\n");
}else{
perror("connect");
}
while(1){
if(fork() == 0){
//3.write
while(1){
memset(msg,0,sizeof(msg));
printf("input msg:");
gets(msg);
write(c_fd,msg,strlen(msg));
}
}
//4.read
while(1){
memset(readBuf,0,sizeof(readBuf));
n_read = read(c_fd,readBuf,128);
if(n_read == -1){
perror("read");
exit(-1);
}else{
printf("read meassage:%d,%s\n",n_read,readBuf);
}
}
}
return 0;
}
四:FTP PROGAME
serve.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
//#include <config.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#define LS 0
#define GET 1
#define PWD 2
#define IFGO 3
#define LCD 4
#define LLS 5
#define CD 6
#define PUT 7
#define QUIT 8
#define DOFILE 9
struct MSG
{
int type;
char cmd[1024];
char dataBuf[128];
};
int get_cmd(char *cmd)
{
if(!(strcmp("ls",cmd))) return LS;
if(!(strcmp("pwd",cmd))) return PWD;
if(!(strcmp("quit",cmd))) return QUIT;
if(strstr(cmd,"cd") != NULL) return CD;
if(strstr(cmd,"put") != NULL) return PUT;
if(strstr(cmd,"get") != NULL) return GET;
return 100;
}
char *getDesDir(char *cmsg)
{
char *p;
p = strtok(cmsg," ");
p = strtok(NULL," ");
return p;
}
void msg_handler(struct MSG msg,int fd)
{
char dataBuf[1024] = {0};
char *file = NULL;
int ret;
int fdfile;
printf("cmd:%s\n",msg.cmd);
ret = get_cmd(msg.cmd);
switch(ret){
case LS:
case PWD:
msg.type = 0;
FILE *r = popen(msg.cmd,"r");
fread(msg.cmd,sizeof(msg.cmd),1,r);
write(fd,&msg,sizeof(msg));
break;
case CD:
msg.type = 1;
char *dir = getDesDir(msg.cmd);
printf("dir:%s\n",dir);
chdir(dir);
break;
case GET:
file = getDesDir(msg.cmd);
if(access(file,F_OK) == -1){
strcmp(msg.cmd,"No this file\n");
write(fd,&msg,sizeof(msg));
}else{
msg.type = DOFILE;
fdfile = open(file,O_RDWR);
read(fdfile,dataBuf,sizeof(dataBuf));
close(fdfile);
strcmp(msg.cmd,dataBuf);
write(fd,&msg,sizeof(msg));
}
break;
case PUT:
fdfile = open(getDesDir(msg.cmd),O_RDWR|O_CREAT,0666);
write(fdfile,msg.dataBuf,strlen(dataBuf));
close(fdfile);
break;
case QUIT:
printf("program quit!\n");
exit(-1);
}
}
int main(int argc,char **argv)
{
int s_fd;
int c_fd;
int n_read;
struct MSG msg;
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
if(argc != 3){
printf("param is not correct\n");
exit(-1);
}
memset(&s_addr,0,sizeof(s_addr));
memset(&c_addr,0,sizeof(c_addr));
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1],&s_addr.sin_addr);
s_fd = socket(AF_INET,SOCK_STREAM,0);
if(s_fd == -1){
perror("socket");
}
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
listen(s_fd,10);
int clen = sizeof(struct sockaddr_in);
while(1){
c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);
if(c_fd == -1){
perror("accept");
}
printf("get connect:%s\n",inet_ntoa(c_addr.sin_addr));
if(fork() == 0){
while(1){
memset(msg.cmd,0,sizeof(msg.cmd));
n_read = read(c_fd,&msg,sizeof(msg));
if(n_read == 0){
printf("client out\n");
exit(-1);
}else if(n_read > 0){
msg_handler(msg,c_fd);
}
}
}
}
close(s_fd);
close(c_fd);
return 0;
}
client.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
//#include <config.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#define LS 0
#define GET 1
#define PWD 2
#define IFGO 3
#define LCD 4
#define LLS 5
#define CD 6
#define PUT 7
#define QUIT 8
#define DOFILE 9
struct MSG
{
int type;
char cmd[1024];
char dataBuf[128];
};
int get_cmd(char *cmd)
{
if(!(strcmp("ls",cmd))) return LS;
if(!(strcmp("pwd",cmd))) return PWD;
if(!(strcmp("quit",cmd))) return QUIT;
if(strstr(cmd,"cd") != NULL) return CD;
if(strstr(cmd,"put") != NULL) return PUT;
if(strstr(cmd,"lcd") != NULL) return LCD;
if(strstr(cmd,"lls") != NULL) return LLS;
if(strstr(cmd,"get") != NULL) return GET;
return -1;
}
char *getDesDir(char *cmsg)
{
char *p;
p = strtok(cmsg," ");
p = strtok(NULL," ");
return p;
}
int cmd_handler(struct MSG msg,int fd)
{
char buf[32];
char *file = NULL;
int ret;
int fdfile;
char *dir = NULL;
ret = get_cmd(msg.cmd);
switch(ret){
case LS:
case CD:
case PWD:
msg.type = 0;
write(fd,&msg,sizeof(msg));
break;
case GET:
msg.type = 2;
write(fd,&msg,sizeof(msg));
break;
case PUT:
strcmp(buf,msg.cmd);
dir = getDesDir(buf);
if(access(dir,F_OK) == -1){
printf("No %s\n",dir);
}else{
fdfile = open(dir,O_RDWR);
read(fdfile,msg.dataBuf,sizeof(msg.dataBuf));
close(fdfile);
write(fd,&msg,sizeof(msg));
}
break;
case LLS:
system("ls");
break;
case LCD:
dir = get_cmd(msg.cmd);
chdir(dir);
break;
case QUIT:
strcpy(msg.cmd,"quit");
write(fd,&msg,sizeof(msg));
close(fd);
exit(-1);
}
return ret;
}
void handler_serve_msg(int c_fd,struct MSG msg)
{
int n_read;
int newfilefd;
struct MSG msgget;
n_read = read(c_fd,&msgget,sizeof(msgget));
if(n_read == 0){
printf("serve out quit\n");
exit(-1);
}
else if(msgget.type == DOFILE){
char *p = getDesDir(msgget.cmd);
newfilefd = open(p,O_RDWR|O_CREAT,0600);
write(newfilefd,msgget.cmd,strlen(msgget.cmd));
putchar('>');
fflush(stdout);
}
else{
printf("------------------------------\n");
printf("\n%s\n",msgget.cmd);
printf("------------------------------\n");
putchar('>');
fflush(stdout);
}
}
int main(int argc,char **argv)
{
int s_fd;
int c_fd;
int n_read;
struct MSG msg;
struct sockaddr_in c_addr;
if(argc != 3){
printf("param is not correct\n");
exit(-1);
}
memset(&c_addr,0,sizeof(c_addr));
c_addr.sin_family = AF_INET;
c_addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1],&c_addr.sin_addr);
c_fd = socket(AF_INET,SOCK_STREAM,0);
if(c_fd == -1){
perror("socket");
}
if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in)) == -1){
perror("connect");
exit(-1);
}
printf("connect ...\n");
int mark = 0;
while(1){
memset(msg.cmd,0,sizeof(msg.cmd));
if(mark == 0) printf(">");
gets(msg.cmd);
if(msg.cmd == 0){
if(mark == 0){
printf(">");
continue;
}
}
mark = 1;
int ret = cmd_handler(msg,c_fd);
if(ret > IFGO){
putchar('>');
fflush(stdout);
continue;
}
if(ret == -1){
printf("cmd error\n");
putchar('>');
fflush(stdout);
continue;
}
handler_serve_msg(c_fd,msg);
}
close(c_fd);
return 0;
}
模仿完成FTP的数据交互