TCP
TCP:Transmission Control Protocol 传输控制协议TCP是一种面向连接(连接导向)的、可靠的、基于字节流的运输层(Transport layer)通信协议,由IETF的RFC 793说明(specified)。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,UDP是同一层内另一个重要的传输协议。
套接字
套接字最早是Unix的,window是借鉴过来的。TCP/IP协议族提供三种套接字:流式、数据报式、原始套接字。其中原始套接字允许对底层协议直接访问,一般用于检验新协议或者新设备问题,很少使用。
套接字编程原理:延续文件作用思想,打开-读写-关闭的模式。
构造函数
public socket(AddressFamily 寻址类型, SocketType 套接字类型, ProtocolType 协议类型)。但需要注意的是套接字类型与协议类型并不是可以随便组合。
编译代码
gcc -o server-while-tcp.out server-while-tcp.c
gcc -o client.out client.c
运行程序
./server-while-tcp.out
./client.out 192.168.1.133
修改服务器为多线程模式
优点 :
1.多线程发送数据,即一个服务器对应多个客户端,最多可以同时监听10个客户端。
2.客户端向服务器发起连接请求,成功后打印连接信息。
3.客户端向服务器发送数据后,服务器端打印数据。
4.服务器将得到的数据全部转换为大写后返回到客户端。
5.客户端打印出从服务器端返回的数据。
server(服务器端)源码
#include <sys/types.h> /* 网络编程所需头文件*/
#include <sys/socket.h> /* 网络编程所需头文件*/
#include <string.h>
#include <netinet/in.h> /* 包含类似inet_ntoa函数的头文件 */
#include <arpa/inet.h> /* 包含类似inet_ntoa函数的头文件 */
#include <unistd.h> /* 包含close函数、forck函数等系统调用函数的头文件 */
#include <stdio.h>
#include <signal.h> /* 包含signal函数的头文件 */
#define SERVER_PORT 8888 /* 监听端口号 */
#define BACKLOG 10 /* listen函数中最大同时监听连接路数 */
/* socket
* bind
* listen
* accept
* send/recv
*/
int charup(unsigned char ch[1000]);
int main(int argc, char **argv)
{
int iSocketServer;
int iSocketClient;
struct sockaddr_in tSocketServerAddr; /* 存放服务器端的通讯协议族、要监听的端口号等信息的结构体 */
struct sockaddr_in tSocketClientAddr; /* 存放连接的客户端的IP地址等信息的结构体 */
int iRet;
int iAddrLen;
int iRecvLen;
unsigned char ucRecvBuf[1000];
int iClientNum = -1;
signal(SIGCHLD, SIG_IGN); /* 处理僵死进程,如果不加,被关闭的客户端所创建的服务器端子进程的资源将不会被父进程回收,导致资源浪费 */
iSocketServer = socket(AF_INET, SOCK_STREAM, 0); /* 创建socket */
if (-1 == iSocketServer)
{
printf("Socket error!\n");
return -1;
}
tSocketServerAddr.sin_family = AF_INET;
tSocketServerAddr.sin_port = htons(SERVER_PORT); /* 将short型的端口数据转换成适合于网络传输的数据类型 */
tSocketServerAddr.sin_addr.s_addr = INADDR_ANY; /* 允许和任何的主机通信 */
memset(tSocketServerAddr.sin_zero, 0, 8); /* 内存置0,确保和struct sockaddr的长度相同 */
iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr)); /* 之前创建的socket文件描述符将被bind修饰 */
if (iRet == -1)
{
printf("Bind error!\n");
return -1;
}
iRet = listen(iSocketServer, BACKLOG); /* 调用listen函数来监听 */
if (-1 == iRet)
{
printf("listen error!\n");
return -1;
}
else
{
printf("Listening & Accepting...\n");
}
while (1)
{
iAddrLen = sizeof(struct sockaddr);
/* 调用accept函数来等待客户端来连接,客户连接成功返回一个值,连接失败返回-1; */
iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
if (-1 != iSocketClient)
{
iClientNum++;
/* 支持多个客户端连接,每有一个就调用fork(),并创建一个子进程 */
printf("Get connnect from NO.%d : %s\n", iClientNum, inet_ntoa(tSocketClientAddr.sin_addr));
if (!fork()) /* 执行到fork()后马上复制一个代码完全一样的子进程*/
{ /* 父进程走fork()=0;子进程走fork()!=0; */
/*子进程的源码*/
while (1)
{
/* 接受客户端发来的数据并显示出来 */
iRecvLen = 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);
}
charup(ucRecvBuf); /* 字符串转大写字母函数 */
iRecvLen = send(iSocketClient, ucRecvBuf, strlen(ucRecvBuf), 0);
if(iRecvLen <= 0)
{
close(iSocketClient);
return -1;
}
}
}
}
}
close(iSocketServer);
return 0;
}
// 定义字符串转大写字母函数
int charup(unsigned char ch[1000])
{
int i = 0;
while (ch[i] != '\0')
{
if(ch[i]>='a'&&ch[i]<='z')
ch[i]=ch[i]-32; //如果你忘记了大小写之间相差32的值,也可以用'a'-'A'来表示
i ++;
}
return 0;
}
client(客户端)源码
#include <sys/types.h> /* 网络编程所需头文件*/
#include <sys/socket.h> /* 网络编程所需头文件*/
#include <string.h>
#include <netinet/in.h> /* 包含类似inet_ntoa函数的头文件 */
#include <arpa/inet.h> /* 包含类似inet_ntoa函数的头文件 */
#include <unistd.h> /* 包含close函数、forck函数等系统调用函数的头文件 */
#include <stdio.h>
#include <signal.h>
#define SERVER_PORT 8888 //同一端口号
/* socket //系统调用
* connect
* listen
* send/recv
*/
int main(int argc, char **argv)
{
int iSocketClient;
struct sockaddr_in tSocketServerAddr;
int iRet; //返回值
unsigned char ucSendBuf[1000];
unsigned char ucRecvBuf[1000];
int iSendLen;
int iRecvLen;
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; //本机上所有IP
if(0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr))
{
printf("invalid server_ip\n");
return -1;
}
memset(tSocketServerAddr.sin_zero, 0 , 8);
iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
if (-1 == iRet)
{
printf("connect error!\n");
printf("%s <server_ip>\n", argv[0]);
return -1;
}
while (1)
{
if(fgets(ucSendBuf, 999, stdin))
{
iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);
if(iSendLen <= 0)
{
close(iSocketClient);
return -1;
}
}
iRecvLen = iRecvLen = recv(iSocketClient, ucRecvBuf, 999, 0);
if (iRecvLen <= 0)
{
close(iSocketClient); //一直接受客户端传来的消息
return -1;
}
else
{
ucRecvBuf[iRecvLen] = '\0'; //加上结束符
printf("Feedback:%s\n", ucRecvBuf);
}
}
return 0;
}
编译代码
gcc -o srv srv.c
gcc -o cli cli.c
运行代码
./srv
./cli 192.168.1.128
提高项
使用${CROSS_COMPILE}编译各个程序
配置代码
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
export PATH=$PATH:/home/suliu/qemu/100ask/100ask_imx6ull-qemu/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin
编译代码
arm-linux-gnueabihf-gcc -o server.o server.c //arm下运行的程序
arm-linux-gnueabihf-gcc -o client.o client.c
gcc -o server.o server.c //ubuntu下运行的程序
gcc -o client.o client.c
echo sever
/* 在服务端打印数据后面加上 */
iRecvLen = send(iSocketClient, ucRecvBuf, strlen(ucRecvBuf), 0);
if(iRecvLen <= 0)
{
close(iSocketClient);
return -1;
}
/* 在客户端发送数据后面加上 */
iRecvLen = iRecvLen = recv(iSocketClient, ucRecvBuf, 999, 0);
if (iRecvLen <= 0)
{
close(iSocketClient); /*一直接受服务器传来的消息*/
return -1;
}
else
{
ucRecvBuf[iRecvLen] = '\0'; /* 加上结束符 */
printf("Feedback:%s\n", ucRecvBuf);
}
echo大写
/* 一个完整字符串大写转换函数 */
#include<stdio.h>
int main()
{
char ch[100];
int i;
while(scanf("%c",&ch[i])!=EOF)
{
if(ch[i]>='a'&&ch[i]<='z')
ch[i]=ch[i]-32;
printf("%c",ch[i]);
}
return 0;
}
/* 修改为我们使用的函数 */
int charup(unsigned char ch[1000]); //声明
charup(ucRecvBuf); //调用
int charup(unsigned char ch[1000])
{
int i = 0;
while (ch[i] != '\0')
{
if(ch[i]>='a'&&ch[i]<='z')
ch[i]=ch[i]-32;
i ++;
}
return 0;
}