# 查看while源代码
.tgz压缩包解压方法:tar zxvf **.tgz
TCP(传输控制协议)
TCP旨在适应支持多网络应用的分层协议层次结构。 连接到不同但互连的计算机通信网络的主计算机中的成对进程之间依靠TCP提供可靠的通信服务。TCP假设它可以从较低级别的协议获得简单的,可能不可靠的数据报服务。 原则上,TCP应该能够在从硬线连接到分组交换或电路交换网络的各种通信系统之上操作。
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#define portnumber 3333
int main(int argc, char* argv[]) {
int local_listen_socket, server_session_socket;
struct sockaddr_in server_addr_info_struct;
struct sockaddr_in client_addr_info_struct;
int size_of_sockaddr_in;
int read_got_bytes_nr;
char buffer[1024];
/* socket: 服务器端开始建立sockfd描述符 */
if ((local_listen_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) { // AF_INET i.e. IPV4; SOCK_STREAM i.e. TCP
fprintf(stderr, "Socket error:%s\n\a", strerror(errno));
exit(1);
}
/* 准备 sockaddr结构及其内部IP、端口信息 */
bzero(&server_addr_info_struct, sizeof(struct sockaddr_in)); // 初始化,置0
server_addr_info_struct.sin_family = AF_INET; // Internet
server_addr_info_struct.sin_addr.s_addr = htonl(INADDR_ANY); // 将本机host上的long数据转化为网络上的long数据,使服务器程序能运行在不同CPU的主机上
// INADDR_ANY 表示主机监听任意/所有IP地址。
//server_addr_info_struct.sin_addr.s_addr=inet_addr("192.168.1.1"); //用于绑定到一个固定IP,inet_addr用于把数字加格式的ip转化为整形ip
server_addr_info_struct.sin_port = htons(portnumber); // (将本机器上的short数据转化为网络上的short数据)端口号
/* bind: 绑定sockfd描述符 和 IP、端口 */
if (bind(local_listen_socket, (struct sockaddr*)(&server_addr_info_struct), sizeof(struct sockaddr)) == -1) {
fprintf(stderr, "ERR bind():%s\n\a", strerror(errno));
exit(1);
}
/* 设置允许连接的最大客户端数 */
if (listen(local_listen_socket, 5) == -1) {
fprintf(stderr, "ERR listen():%s\n\a", strerror(errno));
exit(1);
}
while (1) {
size_of_sockaddr_in = sizeof(struct sockaddr_in);
fprintf(stderr, "Listening & Accepting...\n");
if ((server_session_socket = accept(local_listen_socket, (struct sockaddr*)(&client_addr_info_struct), &size_of_sockaddr_in)) == -1) { // 服务器阻塞, 直到接受到客户连接
fprintf(stderr, "ERR accept():%s\n\a", strerror(errno));
exit(1);
}
fprintf(stderr, "Got connection from %s\n", inet_ntoa(client_addr_info_struct.sin_addr)); // 网络地址 转换成 字符串
if ((read_got_bytes_nr = read(server_session_socket, buffer, 1024)) == -1) {
fprintf(stderr, "ERR read():%s\n", strerror(errno));
exit(1);
}
buffer[read_got_bytes_nr] = '\0';
printf("Server received %s\n", buffer); /* 这个对话服务已经结束 */
close(server_session_socket); /* 下一个 */
}
/* 结束通讯 */
close(local_listen_socket);
exit(0);
}
# 编译并在ubuntu下运行
- 编译
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.*** //新的窗口打开
## 修改服务器为多线程模式
-
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 server server.c gcc -o clien clien.c
-
./servr ./clien 192.168.116.*** //新的窗口打开
-