1. C语言中int main(int argc, char *argv[])中这两个参数是什么意思?
argc:命令行参数的个数,默认值是1
argv:char类型的指针数组,用于保存命令行参数;argv[0]是带路径的程序名称,argv[1]是dos命令行中执行程序名后的第一个字符串,argv[2]是第二个字符串,以此类推.....
这两个参数的作用是:可以接收命令行中输入的参数【好方便啊!】
2. 设置服务器端Socket的地址
【如果只设定服务器机的一个ip地址】
这样设置:serveraddr是结构体sockaddr_in的实例;
而在sockaddr_in结构体中有一个成员sin_addr ,它是结构体in_addr的实例,
地址就保存在结构体sockaddr_in中的结构体sin_addr中的s_addr成员中——
serveraddr.sin_addr.s_addr = htons("192.168.0.10");
【如果要让服务器上的所有ip地址都得到连接请求】
需要一个特殊的地址
#define INADDR_ANY (uint32_t)0x00000000
serveraddr.sin_addr.s_addr = INADDR_ANY;
3. Socket TCP编程 服务端
#include <netdb.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <signal.h>
#include <time.h>
//#define INADDR_ANY (uint32_t)0x00000000
int sockfd;
void sig_handler(int signo)
{
if(signo == SIGINT){
printf("server close\n");
/*step 6 close socket*/
close(sockfd);
exit(1);//0 or 1 all can close
}
}
/*output client's messages */
void out_addr(struct sockaddr_in *clientaddr)
{
int port = ntohs(clientaddr->sin_port);//net to host
char ip[16];
memset(ip,0,sizeof(ip));
inet_ntop(AF_INET, &clientaddr->sin_addr.s_addr, ip, sizeof(ip));//net to Dot decimal(same as 192.168.0.1)
printf("client: %s(%d) connected\n", ip, port);
}
void do_service(int fd)
{
long t = time(0);//write server's system time to client
char *s = ctime(&t);
size_t size = strlen(s) * sizeof(char);
if(write(fd, s, size) != size){
perror("write error");
}
}
int main(int argc, char *argv[])
{
if(argc < 2){
printf("usage: %s #port\n", argv[0]);//print program's name
exit(1);
}
if(signal(SIGINT, sig_handler) == SIG_ERR){//SIGINT:ctrl+C can end ; signal function get SIG_ERR if error
perror("signal sigint error"); //perror function is defined in <stdlib.h>,we can see" str: error message"
exit(1);
}
/*step 1 creat socket
*socket is a struct in kernel
*AF_INET: IPV4
*SOCK_STREAM: tcp protocol(udp: SOCK_DGRAM)
**/
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0){
perror("socket error");
exit(1);
}
/*step 2 bind()
*bound with socket and address(ip\port\intnet type)
*sockaddr_in is special net_struct for internet */
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr)); //clear
serveraddr.sin_family = AF_INET; //IPV4(Host byte order is ok)
serveraddr.sin_port = htons(atoi(argv[1]));//port from terminal(atoi:string to int)(htons:Host to Network byte order 16bit)
serveraddr.sin_addr.s_addr = INADDR_ANY; //htons("192.168.0.10")
if(bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0){//cast as common address type : sockaddr
perror("bind error");
exit(1);
}
/*step 3 listen()
*tell system to accept connecting request (in server port)
*put connecting request to queue* (10 is the length of queue)
*/
if(listen(sockfd, 10) < 0){
perror("listen error");
exit(1);
}
/*step 4 accept()
*get a connection and return the new socket file descriptor(sockfd)
*This sockfd(client's fd) is different from the sockfd in step 1(server's fd)
*/
struct sockaddr_in clientaddr;
socklen_t clientaddr_len = sizeof(clientaddr);//This is a pointer so we need to use & to get the message
while(1){
int fd = accept(sockfd, (struct sockaddr*)&clientaddr, &clientaddr_len);
if(fd < 0) {
perror("accept error");
continue;
}
/*step 5 IO function: read/write
*/
out_addr(&clientaddr);
do_service(fd);
/*step 6 close socket
*/
close(fd);//client's sockfd
}
return 0;
}
以上程序报错/警告如下:
warning1: “xxx” redefined
INADDR_ANY这个宏在多个文件中重复定义了,可能包含在了多个.h文件中。
解决办法:既然在.h文件中已经有过了宏定义,我就把自己定义的那行注释掉了
warning2: implicit decleration of function 'xxx' 诸如此类报错都是调用的函数未声明造成的。
解决办法:开头加上#include <arpa/inet.h>
最后运行一下~由于没有客户端连进来,服务器一直保持监听状态,ctrl+C可以结束进程。
采用本机的另一个终端中的telnet测试程序,最终返回给客户端一个服务器端的系统时间
采用浏览器与测试程序通信,最终浏览器客户端显示了服务器的系统时间
注意:
1. telnet、http是应用层协议,但可以进行数据通信,架构在TCP协议之上;
2. 127.0.0.1是本机ip,其他机器的客户端想要连接本机的服务器,必须要获取本机真正的ip地址——ifconfig;
3. 服务器端收到的客户端端口号,是系统自动分配的(35304),每次连接都不一样。
明天更新客户端的部分
学习教程来自:b站av36871598