转自:http://blog.csdn.net/liujia2100/article/details/9006479

版权声明:本文为博主原创文章,未经博主允许不得转载。

各个主要函数的功能:

、socket

int socket(int domain, int type,int protocol)     

    domain:说明我们网络程序所在的主机采用的通讯协族(AF_UNIX  和  AF_INET  等).
AF_UNIX 只能够用于单一的 Unix 系统进程间通信,而 AF_INET 是针对 Internet 的,因而可以允
许在远程 主机之间通信(当我们 man socket 时发现 domain 可选项是 PF_*而不是 AF_*,因
为 glibc 是 posix 的实现 所以用 PF 代替了 AF,不过我们都可以使用的). type:我们网络程序所采用的通讯协议(SOCK_STREAM,SOCK_DGRAM 等) SOCK_STREAM
表明我们用的是 TCP 协议,这样会提供按顺序的,可靠,双向,面向连接的比特流. SOCK_DGRAM
表明我们用的是 UDP 协议,这样只会提供定长的,不可靠,无连接的通信. protocol:由于我们指定了 type,所以这个地方我们一般只要用 来代替就可以了
socket 为网络通讯做基本的准备.成功时返回文件描述符,失败时返回-,看 errno 可知道出错
的详细情况. 、bind
int bind(int sockfd, struct sockaddr *my_addr, int addrlen) sockfd:是由 socket 调用返回的文件描述符. addrlen:是 sockaddr 结构的长度. my_addr:是一个指向 sockaddr 的指针. 在中有 sockaddr 的定义 struct sockaddr{
unisgned short as_family;
char sa_data[];
}; 不过由于系统的兼容性, 我们一般不用这个头文件, 而使用另外一个结构(struct sockaddr_in) 来代替.在中有 sockaddr_in 的定义
struct sockaddr_in{
unsigned short sin_family;
unsigned short int sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[]; 我们主要使用 Internet 所以 sin_family 一般为 AF_INET,sin_addr 设置为 INADDR_ANY
表示可以和任何的主机通信,sin_port 是我们要监听的端口号.sin_zero[]是用来填充的. bind
将本地的端口同 socket 返回的文件描述符捆绑在一起.成功是返回 ,失败的情况和 socket 一
样 、listen int listen(int sockfd,int backlog) sockfd:是 bind 后的文件描述符. backlog:设置请求排队的最大长度.当有多个客户端程序和服务端相连时, 使用这个表示
可以介绍的排队长度. listen 函数将 bind 的文件描述符变为监听套接字.返回的情况和 bind 一
样. 、 accept
int accept(int sockfd, struct sockaddr *addr,int *addrlen) sockfd:是 listen 后的文件描述符. addr,addrlen 是用来给客户端的程序填写的,服务器端只要传递指针就可以了. bind,listen
和 accept 是服务器端用的函数,accept 调用时,服务器端的程序会一直阻塞到有一个客户程序
发出了连接. accept 成功时返回最后的服务器端的文件描述符,这个时候服务器端可以向该描
述符写信息了. 失败时返回- 、 connect
int connect(int sockfd, struct sockaddr * serv_addr,int addrlen)
sockfd:socket 返回的文件描述符. serv_addr:储存了服务器端的连接信息.其中 sin_add 是服务端的地址 addrlen:serv_addr 的长度 connect 函数是客户端用来同服务端连接的.成功时返回 ,sockfd 是同服务端通讯的文件
描述符 失败时返回-. 、 gethostbyname 和 gethostbyaddr 都涉及到一个 hostent 的结构体,如下所示: Struct hostent{
char *h_name;/*正式主机名*/
char **h_aliases;/*主机别名*/
int h_addrtype;/*地址类型*/
int h_length;/*地址长度*/
char **h_addr_list;/*指向 IPv4或 IPv6的地址指针数组*/
}
所需头文件 #include <netdb.h> 函数原型 Struct hostent *gethostbyname(const char *hostname) 函数传入值 Hostname:主机名 函数返回值 成功:
hostent 类型指针 出错:− 服务端源码:
[cpp] view plain copy #include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h> int main(int argc, char *argv[])
{
int sockfd,new_fd;
int sockaddr_size;
int ret;
int len;
struct sockaddr_in server_addr; //结构体sockaddr_in 和 aockaddr 是兼容的
struct sockaddr_in client_addr;
int sin_size,portnumber;
char buf[]; fd_set rfds;
struct timeval tv;
int maxfd;
FD_ZERO(&rfds);
FD_SET(STDIN_FILENO, &rfds); if((portnumber = atoi(argv[]))<)
{
printf("port number error, will exit\n");
exit();
}
/* 服务器端开始建立 socket 描述符 */
if((sockfd=socket(AF_INET,SOCK_STREAM,))==-) //AF_INET也可以用PF_INET代替,表明针对錓neternet,可以建立远程连接。SOCK_STREAM表明使用的是TCP协议
{ //而 SOCK_DGRAM 表明我们用的是 UDP 协议
printf("socket, will exit\n");
close(sockfd);
exit();
}
/* 服务器端填充 sockaddr 结构 */
bzero(&server_addr,sizeof(struct sockaddr_in));
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=htonl(INADDR_ANY); //标识可以和任何主机通信
server_addr.sin_port=htons(portnumber); /* 捆绑 sockfd 描述符 */
if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-)
{
printf("bind error, will exit\n");
close(sockfd);
exit();
}
/* 监听 sockfd 描述符 */
if(listen(sockfd,)==-) //设置客户端请求排队的最大长度,允许最大5个
{
printf("listen, will exit\n");
close(sockfd);
exit();
} while()
{
/* 服务器阻塞,直到客户程序建立连接 */
printf("Will go to talk, wait connecting...\n");
sockaddr_size = sizeof(struct sockaddr);
//int accept(int sockfd, struct sockaddr *addr,int *addrlen)
if((new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sockaddr_size))==-)
{
printf("accept error, will exit\n");
close(sockfd);
exit();
}
else
{
printf("server: get connection from %s, port %d, socket %d\n",
(char *)inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port),
new_fd);
}
//进行会话
while()
{ FD_ZERO(&rfds);
FD_SET(STDIN_FILENO, &rfds);
FD_SET(new_fd, &rfds);
//maxfd = new_fd > STDIN_FILENO ? newfd :STDIN_FILENO;
//maxfd = maxfd + 1;
maxfd = new_fd + ; tv.tv_sec = ;
tv.tv_usec = ;//设置等待时间
ret = select(maxfd, &rfds, NULL, NULL, &tv);
if(ret<)
{
printf("select error, process will eixt\n");
exit();
}
else if(FD_ISSET(STDIN_FILENO, &rfds))//测试是否有数据
{
bzero(buf,);
//printf("Server :");
fgets(buf, , stdin);
if (!strncasecmp(buf, "quit", ))
{
printf("current talk exit\n");
FD_CLR(new_fd, &rfds);
close(new_fd);
break;
}
//printf("Server :%s\n",buf);
// int recv(int sockfd,void *buf,int len,int flags)
// int send(int sockfd,void *buf,int len,int flags)
//最后一个参数可以是0,也可以是
/* _______________________________________________________________
| MSG_DONTROUTE | 不查找路由表 |
| MSG_OOB | 接受或者发送带外数据 |
| MSG_PEEK | 查看数据,并不从系统缓冲区移走数据 |
| MSG_WAITALL | 等待所有数据 |
|--------------------------------------------------------------|
*/
len = send(new_fd,buf,strlen(buf)-,);
if(len < )
{
printf("send fail\n");
} }
else if(FD_ISSET(new_fd, &rfds))
{ bzero(buf,);
len = recv(new_fd,buf,strlen(buf)-,);
if(len < )
{
printf("receive fail\n");
}
if(len == )//当客户端终止运行的时候,会不断检测到sockfd的状态变化,但是收到的信息长度为0
{
printf("Client has already exit, will exit\n");
FD_CLR(new_fd, &rfds);
close(new_fd);
break; }
if (!strncasecmp(buf, "quit", ))
{
printf("current talk exit\n");
FD_CLR(new_fd, &rfds);
close(new_fd);
break;
}
buf[len+]='\0';
printf(" Client :%s\n",buf); } } } } 客户端:
[cpp] view plain copy #include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h> int main(int argc, char *argv[])
{
int sockfd,new_fd;
int sockaddr_size;
int ret;
int len;
struct sockaddr_in server_addr; //结构体sockaddr_in 和 aockaddr 是兼容的
struct hostent *host;
int sin_size,portnumber;
char buf[]; fd_set rfds;
struct timeval tv;
int maxfd;
FD_ZERO(&rfds);
FD_SET(STDIN_FILENO, &rfds); if((host=gethostbyname(argv[])) == )
{
printf("server ip %s error\n",argv[]);
exit();
} if((portnumber = atoi(argv[]))<)
{
printf("port number error, will exit\n");
exit();
}
/* 客户程序开始建立 sockfd 描述符 */
if((sockfd=socket(AF_INET,SOCK_STREAM,))==-) //AF_INET也可以用PF_INET代替,表明针对錓neternet,可以建立远程连接。SOCK_STREAM表明使用的是TCP协议
{ //而 SOCK_DGRAM 表明我们用的是 UDP 协议
printf("socket, will exit\n");
exit();
}
/* 客户程序填充服务端的资料 */
bzero(&server_addr,sizeof(struct sockaddr_in));
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(portnumber);
server_addr.sin_addr=*((struct in_addr *)host->h_addr); /* 客户程序发起连接请求 */
if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-)
{
printf("connect will exit\n");
exit();
}
printf("start talk...\n"); FD_SET(sockfd, &rfds);
//进行会话
while()
{ FD_ZERO(&rfds);
FD_SET(STDIN_FILENO, &rfds);
FD_SET(sockfd, &rfds); //maxfd = new_fd > STDIN_FILENO ? newfd :STDIN_FILENO;
//maxfd = maxfd + 1;
maxfd = sockfd + ; tv.tv_sec = ;
tv.tv_usec = ;//设置等待时间
ret = select(maxfd, &rfds, NULL, NULL, &tv);
if(ret<)
{
printf("select error, process will eixt\n");
exit();
}
else if(FD_ISSET(STDIN_FILENO, &rfds))//测试是否有数据
{
bzero(buf,);
//printf("Client :");
fgets(buf, , stdin);
if (!strncasecmp(buf, "quit", ))
{
printf("current talk exit\n");
FD_CLR(sockfd, &rfds);
close(sockfd);
break;
}
//printf("Client :%s\n",buf);
// int recv(int sockfd,void *buf,int len,int flags)
// int send(int sockfd,void *buf,int len,int flags)
//最后一个参数可以是0,也可以是
/* _______________________________________________________________
| MSG_DONTROUTE | 不查找路由表 |
| MSG_OOB | 接受或者发送带外数据 |
| MSG_PEEK | 查看数据,并不从系统缓冲区移走数据 |
| MSG_WAITALL | 等待所有数据 |
|--------------------------------------------------------------|
*/
len = send(sockfd,buf,strlen(buf)-,);
if(len < )
{
printf("send fail\n");
} }
else if(FD_ISSET(sockfd, &rfds))
{ bzero(buf,);
len = recv(sockfd,buf,strlen(buf)-,);
if(len < )
{
printf("receive fail\n");
}
if(len == )//当服务器终止运行的时候,会不断检测到sockfd的状态变化,但是收到的信息长度为0
{
printf("Server has already exit, will exit\n");
FD_CLR(sockfd, &rfds);
close(sockfd);
break; }
if (!strncasecmp(buf, "quit", ))
{
printf("current talk exit\n");
FD_CLR(sockfd, &rfds);
close(sockfd);
break;
}
buf[len+]='\0';
printf(" Server: %s\n",buf); } } }

socket 编程 TCP 实现简单聊天功能【转】的更多相关文章

  1. 使用socket编程实现一个简单的文件服务器

    使用socket编程实现一个简单的文件服务器.客户端程序实现put功能(将一个文件从本地传到文件服务器)和get功能(从文件服务器取一远程文件存为本地文件).客户端和文件服务器不在同一台机器上. pu ...

  2. Win Socket编程原理及简单实例

    [转]http://www.cnblogs.com/tornadomeet/archive/2012/04/11/2442140.html 使用Linux Socket做了小型的分布式,如Linux ...

  3. 利用socket.io+nodejs打造简单聊天室

    代码地址如下:http://www.demodashi.com/demo/11579.html 界面展示: 首先展示demo的结果界面,只是简单消息的发送和接收,包括发送文字和发送图片. ws说明: ...

  4. C#版 Socket编程(最简单的Socket通信功能)

    示例程序是同步套接字程序,功能很简单,只是客户端发给服务器一条信息,服务器向客户端返回一条信息:这里只是一个简单的示例,是一个最基本的socket编程流程,在接下来的文章中,会依次记录套接字的同步和异 ...

  5. python socket编程实现的简单tcp迭代server

    与c/c++ socket编程对照见http://blog.csdn.net/aspnet_lyc/article/details/38946915 server: import socket POR ...

  6. Linux C Socket编程原理及简单实例

    部分转自:http://goodcandle.cnblogs.com/archive/2005/12/10/294652.aspx 1.   什么是TCP/IP.UDP? 2.   Socket在哪里 ...

  7. java基础之Socket编程概述以及简单案例

    概述: 用来实现网络互连的 不同的计算机上 运行的程序间 可以进行数据交互  也就是用来在不同的电脑间, 进行数据传输. 三大要素: IP地址: 设备(电脑,手机,ipad)在网络中的唯一标识. 组成 ...

  8. Socket编程 Tcp和粘包

    大多数程序员都要接触网络编程,Web开发天天和http打交道.稍微底层一点的程序员,就是TCP/UDP . 对程序员来说,Tcp/udp的核心是Socket编程. 我的浅薄的观点---------理解 ...

  9. 3、linux下Socket编程-TCP/UDP

    1.什么是Socket 网络的 Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符.Socket也具有一个类似于打开文件的函数调用Socket(),该函数返 回一个整型的Socke ...

随机推荐

  1. [OS] 操作系统-进程线程-经典面试笔试题

    题目转自:http://blog.csdn.net/morewindows/article/details/7392749 ·线程的基本概念.线程的基本状态及状态之间的关系? 线程,有时称为轻量级进程 ...

  2. html5 拖拽练习题

    html5新的拖拽 只支持Internet Explorer 9.Firefox.Opera 12.Chrome 以及 Safari 5 支持拖放. 来一个实例: <!DOCTYPE html& ...

  3. 第二章 IoC

    什么是IoC 如何配置IOC Bean的生命周期 多环境配置 条件化配置Bean 什么是IOC? IOC有两层含义, 1.控制反转:将对象实例的创建与销毁的权限交给Spring容器管理,而不再是调用对 ...

  4. 前端基础:CSS属性操作

    CSS属性操作 1.文本 文本颜色:color,颜色属性被用来设置文字的颜色,颜色是通过CSS经常指定的,其格式有: 1.十六进制:#FF0000: 2.RGB值:RGB(255,0,0): 3.颜色 ...

  5. ARC077C pushpush 递推

    ---题面--- 题解: 貌似一般c题都是递推... 观察到最后一个插入的数一定在第一个,倒数第二个插入的数一定在倒数第一个,倒数第三个插入的数一定在第2个,倒数第四个插入的数一定在倒数第2个…… O ...

  6. 【BZOJ5301】【CQOI2018】异或序列(莫队)

    [BZOJ5301][CQOI2018]异或序列(莫队) 题面 BZOJ 洛谷 Description 已知一个长度为 n 的整数数列 a[1],a[2],-,a[n] ,给定查询参数 l.r ,问在 ...

  7. POJ3686:The Windy's——题解

    http://poj.org/problem?id=3686 题目大意: 有n个订单m个厂子,第i个订单在第j个厂子所需时间为zij,一个厂子做一个订单时不能做其他的订单. 求订单平均时间最小值. — ...

  8. POJ3421:X-factor Chains——题解

    http://poj.org/problem?id=3421 题目大意:一个数列,起始为1,终止为一给定数X,满足Xi < Xi+1 并且Xi | Xi+1. 求出数列最大长度和该长度下的情况数 ...

  9. [bzoj] 2049 洞穴勘探 || LCT

    原题 这是一道LCT的板子题. 至于LCT--link cut tree,也叫动态树,用splay实现动态连边的树. 预备知识: 实边:一个非叶节点,向它的儿子中的一个连一条特殊的边,称为实边;该非叶 ...

  10. Myhchael原创题系列 Mychael vs Kid 【题解】

    题目链接 Mychael vs Kid 题解 先说说这题的由来及前身 前身 首先有一个很经典的题目: 维护区间加,查询区间\(gcd\) 如果强行用线段树维护的话,区间加之后就没法直接确定当前区间的\ ...