本文不涉及太多原理性的记录,纯属从代码入手解析,个人的理解。
【基本知识】TCP协议与UDP协议数据传输方式(本笔记只了解TCP协议)
1.网络中两台主机之间的数据传输方式主要有两种:面向连接TCP,可靠的和面向无连接UDP,不可靠的。
eg:UDP传输:qq视频聊天就是采用UDP传输的;假如是TCP传输,当你网络差时(由于TCP的传输是面向连接、可靠的),所以会导致下一帧视频显示时间往后推,导致聊天对象所看到的画面是不实时的,所以,视频聊天采用UDP传输。
TCP:你传输的文件是采用TCP方式传输的,毕竟你不想得到数据是不完整的。
2.数据传输3要素:目的,源,长度
【代码解剖】
【server.c】
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
/* 1.socket
*2.设置本地地址信息
* 3.bind
* 4.listen
* 5.accept
* 6.send/recv
*/
#define SERVER_PORT 8888
#define BACKLOG 10
int main(int argc, char **argv)
{
int iSocketServer;
int iSocketClient;
struct sockaddr_in tSocketServerAddr;/* 设置本地地址信息 */
struct sockaddr_in tSocketClientAddr;
int iRet;
int iAddrLen;
int iRecvLen;
unsigned char ucRecvBuf[1000];
int iClientNum = -1;
/*防止僵死进程:方法一,我们把这个信号忽略
*服务器采用了fork的话,要收集垃圾进程,防止僵尸进程的产生,可以这样处理:
*/
/* 1. 获得套接字描述符 */
iSocketServer = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == iSocketServer)
{
printf("socket error!\n");
return -1;
}
/* 2.设置本地地址信息 */
tSocketServerAddr.sin_family = AF_INET;/* 协议族 */
tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short 端口*/
tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;/* 本机上的所有ip*/
memset(tSocketServerAddr.sin_zero, 0, 8);/* 填充0 */
/* bzero(&(tSocketServerAddr.sin_zero),8) */
/* 3.绑定地址到套接字上描述符上 */
iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
if (-1 == iRet)
{
printf("bind error!\n");
return -1;
}
/* 4.在地址端口上监听 */
iRet = listen(iSocketServer, BACKLOG);
if (-1 == iRet)
{
printf("listen error!\n");
return -1;
}
while (1)
{
iAddrLen = sizeof(struct sockaddr);
iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
/*accept 的返回值是客户端的套接字描述符
*参数1:本机套接字文件描述符
*参数2:客户端的ip 地址保存的地方
*参数3:长度
* 这个函数处于阻塞状态,等待客户机的连接,接受请求
*/
if (-1 != iSocketClient)
{
iClientNum++;/* 统计客户机的个数 */
/* 打印出连接数,以及客户端的ip 地址 */
printf("Get connect from client %d : %s\n", iClientNum, inet_ntoa(tSocketClientAddr.sin_addr));
/* 创建一个子进程复制出一个完全一样的A` 程序
*如果fork() 创建成功,则子进程会走这条分支
*父进程会走else 分支
*创建子进程,在这里仅仅为了了解该知识点
*/
if (!fork())
{
/* 子进程的源码 */
while (1)
{
/* 5.接收客户端发来的数据并保存在ucRecvBuf */
iRecvLen = recv(iSocketClient, ucRecvBuf, 999, 0);
if (iRecvLen <= 0)
{
/* 假设客户端没有发数据,则关闭监听 */
close(iSocketClient);
return -1;
}
else
{
/* 有数据则打印出来 */
ucRecvBuf[iRecvLen] = '\0';
printf("Get Msg From Client %d: %s\n", iClientNum, ucRecvBuf);
}
}
}
/* 父进程 */
/*防止进程僵死方法二:
*else
* wait(NULL);
*假如你要看进程退出状态的话,则
*else{
* wait(&status);/* status 子进程结束时返回的终止状态 */
* if(WIFEXITED(status))/* 正常退出 */
* printf("exit status : %d\n",WIFEXITED(status));
* if(WIFSIGNALED(status))/* 子进程被某个信号终止 */
* printf("signal number : %d\n",WIFSIGNALED(status));
*}
*/
}
}
close(iSocketServer);
return 0;
}
【client.c】
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
/* socket :创建套接字
* connect:向服务器发送连接
* tSocketServerAddr:设置服务器的地址结构
* send/recv :接受/发送信息
*/
#define SERVER_PORT 8888
int main(int argc, char **argv)
{
int iSocketClient;
struct sockaddr_in tSocketServerAddr;
int iRet;
unsigned char ucSendBuf[1000];
int iSendLen;
if (argc != 2)
{
printf("Usage:\n");
printf("%s <server_ip>\n", argv[0]);
return -1;
}
iSocketClient = socket(AF_INET, SOCK_STREAM, 0);
tSocketServerAddr.sin_family = AF_INET;/* 协议族 */
tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short 端口*/
//tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr))/* 把ip 地址字符串转换 struct in_addr 类型,并存储在tSocketServerAddr.sin_addr*/
{
/* 不成功 非法服务器ip */
printf("invalid server_ip\n");
return -1;
}
memset(tSocketServerAddr.sin_zero, 0, 8);
/* 客户端向服务端发起连接请求 */
/* iSocketClient文件标识符,句柄 ;tSocketServerAddr 保存服务器地址端口等信息;sockaddr):长度*/
iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
if (-1 == iRet)
{
printf("connect error!\n");
return -1;
}
while (1)
{
/* 从标准输入那儿获得数据 */
if (fgets(ucSendBuf, 999, stdin))
{
/* 发送数据 */
iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);
if (iSendLen <= 0)
{
close(iSocketClient);
return -1;
}
}
}
return 0;
}